activitybarPart.ts 19.4 KB
Newer Older
E
Erich Gamma 已提交
1 2 3 4 5 6 7
/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/

'use strict';

B
Benjamin Pasero 已提交
8
import 'vs/css!./media/activitybarpart';
9
import nls = require('vs/nls');
10 11 12
import { TPromise } from 'vs/base/common/winjs.base';
import DOM = require('vs/base/browser/dom');
import * as arrays from 'vs/base/common/arrays';
J
Johannes Rieken 已提交
13
import { illegalArgument } from 'vs/base/common/errors';
14
import { Builder, $, Dimension } from 'vs/base/browser/builder';
J
Johannes Rieken 已提交
15
import { Action } from 'vs/base/common/actions';
J
Joao Moreno 已提交
16
import { ActionsOrientation, ActionBar, IActionItem, Separator } from 'vs/base/browser/ui/actionbar/actionbar';
17
import { ViewletDescriptor } from 'vs/workbench/browser/viewlet';
B
Benjamin Pasero 已提交
18
import { GlobalActivityExtensions, IGlobalActivityRegistry } from 'vs/workbench/browser/activity';
19
import { Registry } from 'vs/platform/platform';
J
Johannes Rieken 已提交
20
import { Part } from 'vs/workbench/browser/part';
21
import { IViewlet } from 'vs/workbench/common/viewlet';
B
Benjamin Pasero 已提交
22
import { ToggleViewletPinnedAction, ViewletActivityAction, ActivityAction, GlobalActivityActionItem, ViewletActionItem, ViewletOverflowActivityAction, ViewletOverflowActivityActionItem, GlobalActivityAction, IViewletActivity } from 'vs/workbench/browser/parts/activitybar/activitybarActions';
B
Benjamin Pasero 已提交
23
import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet';
24
import { IActivityBarService, IBadge } from 'vs/workbench/services/activity/common/activityBarService';
25
import { IPartService, Position as SideBarPosition } from 'vs/workbench/services/part/common/partService';
J
Johannes Rieken 已提交
26
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
27
import { IExtensionService } from 'vs/platform/extensions/common/extensions';
28 29 30 31
import { IStorageService } from 'vs/platform/storage/common/storage';
import { Scope as MementoScope } from 'vs/workbench/common/memento';
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
import { StandardMouseEvent } from 'vs/base/browser/mouseEvent';
J
Joao Moreno 已提交
32
import { dispose, IDisposable, toDisposable } from 'vs/base/common/lifecycle';
33
import { ToggleActivityBarVisibilityAction } from 'vs/workbench/browser/actions/toggleActivityBarVisibility';
34
import { IThemeService } from 'vs/platform/theme/common/themeService';
35
import { ACTIVITY_BAR_BACKGROUND, ACTIVITY_BAR_BORDER } from 'vs/workbench/common/theme';
36
import { contrastBorder } from 'vs/platform/theme/common/colorRegistry';
E
Erich Gamma 已提交
37

38
export class ActivitybarPart extends Part implements IActivityBarService {
39

40
	private static readonly ACTIVITY_ACTION_HEIGHT = 50;
41
	private static readonly PINNED_VIEWLETS = 'workbench.activity.pinnedViewlets';
42

43
	public _serviceBrand: any;
P
Pine Wu 已提交
44

45 46
	private dimension: Dimension;

47 48 49
	private globalActionBar: ActionBar;
	private globalActivityIdToActions: { [globalActivityId: string]: GlobalActivityAction; };

I
isidor 已提交
50
	private viewletSwitcherBar: ActionBar;
51 52 53
	private viewletOverflowAction: ViewletOverflowActivityAction;
	private viewletOverflowActionItem: ViewletOverflowActivityActionItem;

54
	private viewletIdToActions: { [viewletId: string]: ActivityAction; };
B
Benjamin Pasero 已提交
55
	private viewletIdToActionItems: { [viewletId: string]: IActionItem; };
56
	private viewletIdToActivityStack: { [viewletId: string]: IViewletActivity[]; };
E
Erich Gamma 已提交
57

B
Benjamin Pasero 已提交
58
	private memento: object;
59
	private pinnedViewlets: string[];
60 61
	private activeUnpinnedViewlet: ViewletDescriptor;

E
Erich Gamma 已提交
62
	constructor(
63 64
		id: string,
		@IViewletService private viewletService: IViewletService,
65
		@IExtensionService private extensionService: IExtensionService,
66 67
		@IStorageService private storageService: IStorageService,
		@IContextMenuService private contextMenuService: IContextMenuService,
I
isidor 已提交
68
		@IInstantiationService private instantiationService: IInstantiationService,
B
Benjamin Pasero 已提交
69 70
		@IPartService private partService: IPartService,
		@IThemeService themeService: IThemeService
E
Erich Gamma 已提交
71
	) {
B
Benjamin Pasero 已提交
72
		super(id, { hasTitle: false }, themeService);
E
Erich Gamma 已提交
73

J
Joao Moreno 已提交
74
		this.globalActivityIdToActions = Object.create(null);
75

B
Benjamin Pasero 已提交
76
		this.viewletIdToActionItems = Object.create(null);
77
		this.viewletIdToActions = Object.create(null);
78
		this.viewletIdToActivityStack = Object.create(null);
E
Erich Gamma 已提交
79

80
		this.memento = this.getMemento(this.storageService, MementoScope.GLOBAL);
J
Joao Moreno 已提交
81 82 83 84 85

		const pinnedViewlets = this.memento[ActivitybarPart.PINNED_VIEWLETS] as string[];

		if (pinnedViewlets) {
			this.pinnedViewlets = pinnedViewlets
J
Joao Moreno 已提交
86 87
				// TODO@Ben: Migrate git => scm viewlet
				.map(id => id === 'workbench.view.git' ? 'workbench.view.scm' : id)
J
Joao Moreno 已提交
88 89 90 91 92
				.filter(arrays.uniqueFilter<string>(str => str));

		} else {
			this.pinnedViewlets = this.viewletService.getViewlets().map(v => v.id);
		}
93

E
Erich Gamma 已提交
94 95 96 97 98 99
		this.registerListeners();
	}

	private registerListeners(): void {

		// Activate viewlet action on opening of a viewlet
100
		this.toUnbind.push(this.viewletService.onDidViewletOpen(viewlet => this.onDidViewletOpen(viewlet)));
E
Erich Gamma 已提交
101 102

		// Deactivate viewlet action on close
103
		this.toUnbind.push(this.viewletService.onDidViewletClose(viewlet => this.onDidViewletClose(viewlet)));
P
Pine Wu 已提交
104 105
	}

106 107 108 109 110 111 112 113 114 115 116
	private onDidViewletOpen(viewlet: IViewlet): void {
		const id = viewlet.getId();

		if (this.viewletIdToActions[id]) {
			this.viewletIdToActions[id].activate();
		}

		const activeUnpinnedViewletShouldClose = this.activeUnpinnedViewlet && this.activeUnpinnedViewlet.id !== viewlet.getId();
		const activeUnpinnedViewletShouldShow = !this.getPinnedViewlets().some(v => v.id === viewlet.getId());
		if (activeUnpinnedViewletShouldShow || activeUnpinnedViewletShouldClose) {
			this.updateViewletSwitcher();
E
Erich Gamma 已提交
117 118 119
		}
	}

120 121 122 123 124
	private onDidViewletClose(viewlet: IViewlet): void {
		const id = viewlet.getId();

		if (this.viewletIdToActions[id]) {
			this.viewletIdToActions[id].deactivate();
E
Erich Gamma 已提交
125 126 127
		}
	}

J
Joao Moreno 已提交
128 129 130 131 132 133 134 135 136 137 138
	public showGlobalActivity(globalActivityId: string, badge: IBadge): IDisposable {
		if (!badge) {
			throw illegalArgument('badge');
		}

		const action = this.globalActivityIdToActions[globalActivityId];
		if (!action) {
			throw illegalArgument('globalActivityId');
		}

		action.setBadge(badge);
B
Benjamin Pasero 已提交
139

J
Joao Moreno 已提交
140 141 142
		return toDisposable(() => action.setBadge(undefined));
	}

143
	public showActivity(viewletId: string, badge: IBadge, clazz?: string): IDisposable {
J
Johannes Rieken 已提交
144 145 146
		if (!badge) {
			throw illegalArgument('badge');
		}
147

148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173
		const activity = <IViewletActivity>{ badge, clazz };
		const stack = this.viewletIdToActivityStack[viewletId] || (this.viewletIdToActivityStack[viewletId] = []);
		stack.unshift(activity);

		this.updateActivity(viewletId);

		return {
			dispose: () => {
				const stack = this.viewletIdToActivityStack[viewletId];
				if (!stack) {
					return;
				}
				const idx = stack.indexOf(activity);
				if (idx < 0) {
					return;
				}
				stack.splice(idx, 1);
				if (stack.length === 0) {
					delete this.viewletIdToActivityStack[viewletId];
				}
				this.updateActivity(viewletId);
			}
		};
	}

	private updateActivity(viewletId: string) {
174
		const action = this.viewletIdToActions[viewletId];
175 176 177 178 179 180 181 182 183 184
		if (!action) {
			return;
		}
		const stack = this.viewletIdToActivityStack[viewletId];
		if (!stack || !stack.length) {
			// reset
			action.setBadge(undefined);

		} else {
			// update
185
			const [{ badge, clazz }] = stack;
E
Erich Gamma 已提交
186 187 188 189 190 191 192 193
			action.setBadge(badge);
			if (clazz) {
				action.class = clazz;
			}
		}
	}

	public createContentArea(parent: Builder): Builder {
194 195
		const $el = $(parent);
		const $result = $('.content').appendTo($el);
E
Erich Gamma 已提交
196 197

		// Top Actionbar with action items for each viewlet action
P
Pine Wu 已提交
198
		this.createViewletSwitcher($result.clone());
E
Erich Gamma 已提交
199

200
		// Top Actionbar with action items for each viewlet action
J
Joao Moreno 已提交
201
		this.createGlobalActivityActionBar($result.getHTMLElement());
202

203 204 205 206 207 208 209
		// Contextmenu for viewlets
		$(parent).on('contextmenu', (e: MouseEvent) => {
			DOM.EventHelper.stop(e, true);

			this.showContextMenu(e);
		}, this.toUnbind);

B
Benjamin Pasero 已提交
210 211
		// Allow to drop at the end to move viewlet to the end
		$(parent).on(DOM.EventType.DROP, (e: DragEvent) => {
212
			const draggedViewlet = ViewletActionItem.getDraggedViewlet();
B
Benjamin Pasero 已提交
213 214 215
			if (draggedViewlet) {
				DOM.EventHelper.stop(e, true);

216
				ViewletActionItem.clearDraggedViewlet();
B
Benjamin Pasero 已提交
217 218 219 220 221 222 223 224

				const targetId = this.pinnedViewlets[this.pinnedViewlets.length - 1];
				if (targetId !== draggedViewlet.id) {
					this.move(draggedViewlet.id, this.pinnedViewlets[this.pinnedViewlets.length - 1]);
				}
			}
		});

E
Erich Gamma 已提交
225 226 227
		return $result;
	}

228 229 230 231 232
	public updateStyles(): void {
		super.updateStyles();

		// Part container
		const container = this.getContainer();
233 234
		const background = this.getColor(ACTIVITY_BAR_BACKGROUND);
		container.style('background-color', background);
235

236
		const borderColor = this.getColor(ACTIVITY_BAR_BORDER) || this.getColor(contrastBorder);
237
		const isPositionLeft = this.partService.getSideBarPosition() === SideBarPosition.LEFT;
238 239 240 241 242 243 244
		container.style('box-sizing', borderColor && isPositionLeft ? 'border-box' : null);
		container.style('border-right-width', borderColor && isPositionLeft ? '1px' : null);
		container.style('border-right-style', borderColor && isPositionLeft ? 'solid' : null);
		container.style('border-right-color', isPositionLeft ? borderColor : null);
		container.style('border-left-width', borderColor && !isPositionLeft ? '1px' : null);
		container.style('border-left-style', borderColor && !isPositionLeft ? 'solid' : null);
		container.style('border-left-color', !isPositionLeft ? borderColor : null);
245 246
	}

247 248 249 250 251 252 253 254 255 256 257 258 259 260
	private showContextMenu(e: MouseEvent): void {
		const event = new StandardMouseEvent(e);

		const actions: Action[] = this.viewletService.getViewlets().map(viewlet => this.instantiationService.createInstance(ToggleViewletPinnedAction, viewlet));
		actions.push(new Separator());
		actions.push(this.instantiationService.createInstance(ToggleActivityBarVisibilityAction, ToggleActivityBarVisibilityAction.ID, nls.localize('hideActivitBar', "Hide Activity Bar")));

		this.contextMenuService.showContextMenu({
			getAnchor: () => { return { x: event.posx + 1, y: event.posy }; },
			getActions: () => TPromise.as(actions),
			onHide: () => dispose(actions)
		});
	}

I
isidor 已提交
261 262
	private createViewletSwitcher(div: Builder): void {
		this.viewletSwitcherBar = new ActionBar(div, {
B
Benjamin Pasero 已提交
263
			actionItemProvider: (action: Action) => action instanceof ViewletOverflowActivityAction ? this.viewletOverflowActionItem : this.viewletIdToActionItems[action.id],
264
			orientation: ActionsOrientation.VERTICAL,
265 266
			ariaLabel: nls.localize('activityBarAriaLabel', "Active View Switcher"),
			animated: false
E
Erich Gamma 已提交
267 268
		});

269
		this.updateViewletSwitcher();
270 271 272

		// Update viewlet switcher when external viewlets become ready
		this.extensionService.onReady().then(() => this.updateViewletSwitcher());
P
Pine Wu 已提交
273 274
	}

J
Joao Moreno 已提交
275
	private createGlobalActivityActionBar(container: HTMLElement): void {
J
Joao Moreno 已提交
276
		const activityRegistry = Registry.as<IGlobalActivityRegistry>(GlobalActivityExtensions);
277 278 279 280 281
		const descriptors = activityRegistry.getActivities();
		const actions = descriptors
			.map(d => this.instantiationService.createInstance(d))
			.map(a => new GlobalActivityAction(a));

282
		this.globalActionBar = new ActionBar(container, {
283 284 285 286 287 288
			actionItemProvider: a => this.instantiationService.createInstance(GlobalActivityActionItem, a),
			orientation: ActionsOrientation.VERTICAL,
			ariaLabel: nls.localize('globalActions', "Global Actions"),
			animated: false
		});

J
Joao Moreno 已提交
289 290
		actions.forEach(a => {
			this.globalActivityIdToActions[a.id] = a;
291
			this.globalActionBar.push(a);
J
Joao Moreno 已提交
292
		});
293 294
	}

295
	private updateViewletSwitcher() {
296 297 298 299 300
		if (!this.viewletSwitcherBar) {
			// We have not been rendered yet so there is nothing to update.
			return;
		}

301 302 303 304
		let viewletsToShow = this.getPinnedViewlets();

		// Always show the active viewlet even if it is marked to be hidden
		const activeViewlet = this.viewletService.getActiveViewlet();
B
Benjamin Pasero 已提交
305
		if (activeViewlet && !viewletsToShow.some(viewlet => viewlet.id === activeViewlet.getId())) {
306 307 308 309 310
			this.activeUnpinnedViewlet = this.viewletService.getViewlet(activeViewlet.getId());
			viewletsToShow.push(this.activeUnpinnedViewlet);
		} else {
			this.activeUnpinnedViewlet = void 0;
		}
311 312 313 314 315

		// Ensure we are not showing more viewlets than we have height for
		let overflows = false;
		if (this.dimension) {
			const maxVisible = Math.floor(this.dimension.height / ActivitybarPart.ACTIVITY_ACTION_HEIGHT);
316
			overflows = viewletsToShow.length > maxVisible;
317 318

			if (overflows) {
319
				viewletsToShow = viewletsToShow.slice(0, maxVisible - 1 /* make room for overflow action */);
320 321 322 323
			}
		}

		const visibleViewlets = Object.keys(this.viewletIdToActions);
B
Benjamin Pasero 已提交
324
		const visibleViewletsChange = !arrays.equals(viewletsToShow.map(viewlet => viewlet.id), visibleViewlets);
325 326 327 328 329 330 331 332 333 334 335

		// Pull out overflow action if there is a viewlet change so that we can add it to the end later
		if (this.viewletOverflowAction && visibleViewletsChange) {
			this.viewletSwitcherBar.pull(this.viewletSwitcherBar.length() - 1);

			this.viewletOverflowAction.dispose();
			this.viewletOverflowAction = null;

			this.viewletOverflowActionItem.dispose();
			this.viewletOverflowActionItem = null;
		}
336

337
		// Pull out viewlets that overflow or got hidden
338 339 340
		const viewletIdsToShow = viewletsToShow.map(v => v.id);
		visibleViewlets.forEach(viewletId => {
			if (viewletIdsToShow.indexOf(viewletId) === -1) {
P
Pine Wu 已提交
341 342 343 344
				this.pullViewlet(viewletId);
			}
		});

345
		// Built actions for viewlets to show
346
		const newViewletsToShow = viewletsToShow
347
			.filter(viewlet => !this.viewletIdToActions[viewlet.id])
P
Pine Wu 已提交
348 349
			.map(viewlet => this.toAction(viewlet));

350 351
		// Update when we have new viewlets to show
		if (newViewletsToShow.length) {
352

353 354 355 356 357 358 359 360 361 362
			// Add to viewlet switcher
			this.viewletSwitcherBar.push(newViewletsToShow, { label: true, icon: true });

			// Make sure to activate the active one
			const activeViewlet = this.viewletService.getActiveViewlet();
			if (activeViewlet) {
				const activeViewletEntry = this.viewletIdToActions[activeViewlet.getId()];
				if (activeViewletEntry) {
					activeViewletEntry.activate();
				}
363
			}
364 365 366

			// Make sure to restore activity
			Object.keys(this.viewletIdToActions).forEach(viewletId => {
367
				this.updateActivity(viewletId);
368 369 370 371 372
			});
		}

		// Add overflow action as needed
		if (visibleViewletsChange && overflows) {
373
			this.viewletOverflowAction = this.instantiationService.createInstance(ViewletOverflowActivityAction, () => this.viewletOverflowActionItem.showMenu());
374
			this.viewletOverflowActionItem = this.instantiationService.createInstance(ViewletOverflowActivityActionItem, this.viewletOverflowAction, () => this.getOverflowingViewlets(), (viewlet: ViewletDescriptor) => this.viewletIdToActivityStack[viewlet.id] && this.viewletIdToActivityStack[viewlet.id][0].badge);
375 376

			this.viewletSwitcherBar.push(this.viewletOverflowAction, { label: true, icon: true });
377
		}
P
Pine Wu 已提交
378 379
	}

380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397
	private getOverflowingViewlets(): ViewletDescriptor[] {
		const viewlets = this.getPinnedViewlets();
		if (this.activeUnpinnedViewlet) {
			viewlets.push(this.activeUnpinnedViewlet);
		}
		const visibleViewlets = Object.keys(this.viewletIdToActions);

		return viewlets.filter(viewlet => visibleViewlets.indexOf(viewlet.id) === -1);
	}

	private getVisibleViewlets(): ViewletDescriptor[] {
		const viewlets = this.viewletService.getViewlets();
		const visibleViewlets = Object.keys(this.viewletIdToActions);

		return viewlets.filter(viewlet => visibleViewlets.indexOf(viewlet.id) >= 0);
	}

	private getPinnedViewlets(): ViewletDescriptor[] {
B
Benjamin Pasero 已提交
398
		return this.pinnedViewlets.map(viewletId => this.viewletService.getViewlet(viewletId)).filter(v => !!v); // ensure to remove those that might no longer exist
399 400
	}

P
Pine Wu 已提交
401
	private pullViewlet(viewletId: string): void {
402
		const index = Object.keys(this.viewletIdToActions).indexOf(viewletId);
B
Benjamin Pasero 已提交
403 404
		if (index >= 0) {
			this.viewletSwitcherBar.pull(index);
405

B
Benjamin Pasero 已提交
406 407 408
			const action = this.viewletIdToActions[viewletId];
			action.dispose();
			delete this.viewletIdToActions[viewletId];
409

B
Benjamin Pasero 已提交
410
			const actionItem = this.viewletIdToActionItems[action.id];
B
Benjamin Pasero 已提交
411
			actionItem.dispose();
B
Benjamin Pasero 已提交
412
			delete this.viewletIdToActionItems[action.id];
B
Benjamin Pasero 已提交
413
		}
I
isidor 已提交
414
	}
J
Joao Moreno 已提交
415

416
	private toAction(viewlet: ViewletDescriptor): ActivityAction {
417
		const action = this.instantiationService.createInstance(ViewletActivityAction, viewlet);
I
isidor 已提交
418

419
		this.viewletIdToActionItems[action.id] = this.instantiationService.createInstance(ViewletActionItem, action);
420
		this.viewletIdToActions[viewlet.id] = action;
I
isidor 已提交
421 422

		return action;
423 424
	}

425 426 427 428
	public getPinned(): string[] {
		return this.pinnedViewlets;
	}

429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454
	public unpin(viewletId: string): void {
		if (!this.isPinned(viewletId)) {
			return;
		}

		const activeViewlet = this.viewletService.getActiveViewlet();
		const defaultViewletId = this.viewletService.getDefaultViewletId();
		const visibleViewlets = this.getVisibleViewlets();

		let unpinPromise: TPromise<any>;

		// Case: viewlet is not the active one or the active one is a different one
		// Solv: we do nothing
		if (!activeViewlet || activeViewlet.getId() !== viewletId) {
			unpinPromise = TPromise.as(null);
		}

		// Case: viewlet is not the default viewlet and default viewlet is still showing
		// Solv: we open the default viewlet
		else if (defaultViewletId !== viewletId && this.isPinned(defaultViewletId)) {
			unpinPromise = this.viewletService.openViewlet(defaultViewletId, true);
		}

		// Case: we closed the last visible viewlet
		// Solv: we hide the sidebar
		else if (visibleViewlets.length === 1) {
455
			unpinPromise = this.partService.setSideBarHidden(true);
456 457 458 459 460 461 462 463 464 465
		}

		// Case: we closed the default viewlet
		// Solv: we open the next visible viewlet from top
		else {
			unpinPromise = this.viewletService.openViewlet(visibleViewlets.filter(viewlet => viewlet.id !== viewletId)[0].id, true);
		}

		unpinPromise.then(() => {

466 467 468
			// then remove from pinned and update switcher
			const index = this.pinnedViewlets.indexOf(viewletId);
			this.pinnedViewlets.splice(index, 1);
469 470 471 472 473 474

			this.updateViewletSwitcher();
		});
	}

	public isPinned(viewletId: string): boolean {
475
		return this.pinnedViewlets.indexOf(viewletId) >= 0;
476 477
	}

B
Benjamin Pasero 已提交
478
	public pin(viewletId: string, update = true): void {
479 480 481 482 483 484 485 486
		if (this.isPinned(viewletId)) {
			return;
		}

		// first open that viewlet
		this.viewletService.openViewlet(viewletId, true).then(() => {

			// then update
487 488
			this.pinnedViewlets.push(viewletId);
			this.pinnedViewlets = arrays.distinct(this.pinnedViewlets);
489

B
Benjamin Pasero 已提交
490 491 492
			if (update) {
				this.updateViewletSwitcher();
			}
493 494 495
		});
	}

496
	public move(viewletId: string, toViewletId: string): void {
B
Benjamin Pasero 已提交
497 498 499 500 501 502

		// Make sure a moved viewlet gets pinned
		if (!this.isPinned(viewletId)) {
			this.pin(viewletId, false /* defer update, we take care of it */);
		}

503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520
		const fromIndex = this.pinnedViewlets.indexOf(viewletId);
		const toIndex = this.pinnedViewlets.indexOf(toViewletId);

		this.pinnedViewlets.splice(fromIndex, 1);
		this.pinnedViewlets.splice(toIndex, 0, viewletId);

		// Clear viewlets that are impacted by the move
		const visibleViewlets = Object.keys(this.viewletIdToActions);
		for (let i = Math.min(fromIndex, toIndex); i < visibleViewlets.length; i++) {
			this.pullViewlet(visibleViewlets[i]);
		}

		// timeout helps to prevent artifacts from showing up
		setTimeout(() => {
			this.updateViewletSwitcher();
		}, 0);
	}

521 522 523 524 525 526 527 528 529 530 531 532 533 534 535
	/**
	 * Layout title, content and status area in the given dimension.
	 */
	public layout(dimension: Dimension): Dimension[] {

		// Pass to super
		const sizes = super.layout(dimension);

		this.dimension = sizes[1];

		// Update switcher to handle overflow issues
		this.updateViewletSwitcher();

		return sizes;
	}
I
isidor 已提交
536

E
Erich Gamma 已提交
537
	public dispose(): void {
I
isidor 已提交
538 539 540 541 542
		if (this.viewletSwitcherBar) {
			this.viewletSwitcherBar.dispose();
			this.viewletSwitcherBar = null;
		}

B
Benjamin Pasero 已提交
543 544 545 546 547
		if (this.globalActionBar) {
			this.globalActionBar.dispose();
			this.globalActionBar = null;
		}

E
Erich Gamma 已提交
548 549
		super.dispose();
	}
550 551 552 553

	public shutdown(): void {

		// Persist Hidden State
554
		this.memento[ActivitybarPart.PINNED_VIEWLETS] = this.pinnedViewlets;
555 556 557 558

		// Pass to super
		super.shutdown();
	}
559
}