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

import * as nls from 'vs/nls';
import { TPromise } from 'vs/base/common/winjs.base';
import * as errors from 'vs/base/common/errors';
9 10
import * as DOM from 'vs/base/browser/dom';
import { $, Dimension, Builder } from 'vs/base/browser/builder';
11
import { Scope } from 'vs/workbench/common/memento';
12 13
import { dispose, IDisposable } from 'vs/base/common/lifecycle';
import { IAction, IActionRunner } from 'vs/base/common/actions';
14
import { IActionItem } from 'vs/base/browser/ui/actionbar/actionbar';
15
import { ITree } from 'vs/base/parts/tree/browser/tree';
J
Joao Moreno 已提交
16
import { firstIndex } from 'vs/base/common/arrays';
17
import { DelayedDragHandler } from 'vs/base/browser/dnd';
S
Sandeep Somavarapu 已提交
18
import { IExtensionService } from 'vs/platform/extensions/common/extensions';
19 20
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
21
import { ViewsRegistry, ViewLocation, IViewDescriptor } from 'vs/workbench/browser/parts/views/viewsRegistry';
22 23 24 25
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { IThemeService } from 'vs/platform/theme/common/themeService';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
26
import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace';
S
#27823  
Sandeep Somavarapu 已提交
27
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
28
import { StandardMouseEvent } from 'vs/base/browser/mouseEvent';
29 30
import { PanelViewlet, ViewletPanel } from 'vs/workbench/browser/parts/views/panelViewlet';
import { IPanelOptions } from 'vs/base/browser/ui/splitview/panelview';
31

32
export interface IViewOptions extends IPanelOptions {
S
#27823  
Sandeep Somavarapu 已提交
33 34 35 36
	id: string;
	name: string;
	actionRunner: IActionRunner;
}
37

38 39
export interface IViewConstructorSignature<T extends ViewsViewletPanel> {
	new(options: IViewOptions, ...services: { _serviceBrand: any; }[]): T;
S
#27823  
Sandeep Somavarapu 已提交
40
}
41

42
export abstract class ViewsViewletPanel extends ViewletPanel {
43

S
#27823  
Sandeep Somavarapu 已提交
44
	readonly id: string;
45
	readonly name: string;
46
	protected treeContainer: HTMLElement;
J
Joao Moreno 已提交
47 48

	// TODO@sandeep why is tree here? isn't this coming only from TreeView
49 50
	protected tree: ITree;
	protected isDisposed: boolean;
51
	private _isVisible: boolean;
52 53 54
	private dragHandler: DelayedDragHandler;

	constructor(
55
		options: IViewOptions,
56
		protected keybindingService: IKeybindingService,
S
#27823  
Sandeep Somavarapu 已提交
57
		protected contextMenuService: IContextMenuService
58
	) {
59
		super(options.name, options, keybindingService, contextMenuService);
60

S
#27823  
Sandeep Somavarapu 已提交
61
		this.id = options.id;
62
		this.name = options.name;
J
Joao Moreno 已提交
63
		this._expanded = options.expanded;
64 65
	}

66 67 68
	setExpanded(expanded: boolean): void {
		this.updateTreeVisibility(this.tree, expanded);
		super.setExpanded(expanded);
69 70
	}

71 72
	protected renderHeader(container: HTMLElement): void {
		super.renderHeader(container);
73 74

		// Expand on drag over
75
		this.dragHandler = new DelayedDragHandler(container, () => this.setExpanded(true));
76 77 78
	}

	protected renderViewTree(container: HTMLElement): HTMLElement {
S
#27823  
Sandeep Somavarapu 已提交
79 80 81
		const treeContainer = document.createElement('div');
		container.appendChild(treeContainer);
		return treeContainer;
82 83
	}

J
Joao 已提交
84
	getViewer(): ITree {
85 86 87
		return this.tree;
	}

J
Joao 已提交
88
	isVisible(): boolean {
89 90 91
		return this._isVisible;
	}

J
Joao 已提交
92
	setVisible(visible: boolean): TPromise<void> {
93 94
		if (this._isVisible !== visible) {
			this._isVisible = visible;
95
			this.updateTreeVisibility(this.tree, visible && this.isExpanded());
S
#27823  
Sandeep Somavarapu 已提交
96
		}
97 98 99 100

		return TPromise.as(null);
	}

101 102
	focus(): void {
		super.focus();
S
#27823  
Sandeep Somavarapu 已提交
103
		this.focusTree();
104 105 106
	}

	protected reveal(element: any, relativeTop?: number): TPromise<void> {
S
#27823  
Sandeep Somavarapu 已提交
107 108 109 110 111
		if (!this.tree) {
			return TPromise.as(null); // return early if viewlet has not yet been created
		}

		return this.tree.reveal(element, relativeTop);
112 113
	}

J
Joao 已提交
114
	layoutBody(size: number): void {
S
Sandeep Somavarapu 已提交
115 116 117 118
		if (this.tree) {
			this.treeContainer.style.height = size + 'px';
			this.tree.layout(size);
		}
119 120
	}

J
Joao 已提交
121
	getActions(): IAction[] {
122 123 124
		return [];
	}

J
Joao 已提交
125
	getSecondaryActions(): IAction[] {
126 127 128
		return [];
	}

J
Joao 已提交
129
	getActionItem(action: IAction): IActionItem {
130 131 132
		return null;
	}

J
Joao 已提交
133
	getActionsContext(): any {
J
Joao Moreno 已提交
134 135 136
		return undefined;
	}

J
Joao 已提交
137
	getOptimalWidth(): number {
138 139 140
		return 0;
	}

141 142 143 144 145 146 147 148
	create(): TPromise<void> {
		return TPromise.as(null);
	}

	shutdown(): void {
		// Subclass to implement
	}

J
Joao 已提交
149
	dispose(): void {
150 151
		this.isDisposed = true;
		this.treeContainer = null;
152 153 154 155

		if (this.tree) {
			this.tree.dispose();
		}
156 157 158 159 160 161 162 163

		if (this.dragHandler) {
			this.dragHandler.dispose();
		}

		super.dispose();
	}

S
#27823  
Sandeep Somavarapu 已提交
164 165 166 167
	private updateTreeVisibility(tree: ITree, isVisible: boolean): void {
		if (!tree) {
			return;
		}
168

S
#27823  
Sandeep Somavarapu 已提交
169 170 171 172 173
		if (isVisible) {
			$(tree.getHTMLElement()).show();
		} else {
			$(tree.getHTMLElement()).hide(); // make sure the tree goes out of the tabindex world by hiding it
		}
174

S
#27823  
Sandeep Somavarapu 已提交
175 176 177 178 179
		if (isVisible) {
			tree.onVisible();
		} else {
			tree.onHidden();
		}
180 181
	}

S
#27823  
Sandeep Somavarapu 已提交
182 183 184 185
	private focusTree(): void {
		if (!this.tree) {
			return; // return early if viewlet has not yet been created
		}
186

S
#27823  
Sandeep Somavarapu 已提交
187 188 189 190 191
		// Make sure the current selected element is revealed
		const selection = this.tree.getSelection();
		if (selection.length > 0) {
			this.reveal(selection[0], 0.5).done(null, errors.onUnexpectedError);
		}
192

S
#27823  
Sandeep Somavarapu 已提交
193 194 195
		// Pass Focus to Viewer
		this.tree.DOMFocus();
	}
196 197
}

S
#27823  
Sandeep Somavarapu 已提交
198
export interface IViewletViewOptions extends IViewOptions {
B
Benjamin Pasero 已提交
199
	viewletSettings: object;
200 201
}

J
Joao Moreno 已提交
202
export interface IViewState {
203
	collapsed: boolean;
J
Joao 已提交
204
	size: number | undefined;
205
	isHidden: boolean;
206
	order: number;
207 208
}

209
export class ViewsViewlet extends PanelViewlet {
210

S
Sandeep Somavarapu 已提交
211
	private viewHeaderContextMenuListeners: IDisposable[] = [];
B
Benjamin Pasero 已提交
212
	private viewletSettings: object;
213
	private readonly viewsContextKeys: Set<string> = new Set<string>();
214
	private viewsViewletPanels: ViewsViewletPanel[] = [];
J
Joao Moreno 已提交
215
	private didLayout = false;
J
Joao Moreno 已提交
216
	protected viewsStates: Map<string, IViewState> = new Map<string, IViewState>();
S
Sandeep Somavarapu 已提交
217
	private areExtensionsReady: boolean = false;
218 219 220 221

	constructor(
		id: string,
		private location: ViewLocation,
222
		private showHeaderInTitleWhenSingleView: boolean,
223 224 225 226
		@ITelemetryService telemetryService: ITelemetryService,
		@IStorageService protected storageService: IStorageService,
		@IInstantiationService protected instantiationService: IInstantiationService,
		@IThemeService themeService: IThemeService,
227
		@IContextKeyService protected contextKeyService: IContextKeyService,
J
Joao Moreno 已提交
228
		@IContextMenuService protected contextMenuService: IContextMenuService,
229
		@IExtensionService protected extensionService: IExtensionService
230
	) {
J
Joao Moreno 已提交
231
		super(id, { showHeaderInTitleWhenSingleView, dnd: true }, telemetryService, themeService);
232

233
		this.viewletSettings = this.getMemento(storageService, Scope.WORKSPACE);
234 235
	}

236
	async create(parent: Builder): TPromise<void> {
S
Sandeep Somavarapu 已提交
237
		await super.create(parent);
238

S
Sandeep Somavarapu 已提交
239
		this._register(this.onDidSashChange(() => this.updateAllViewsSizes()));
240 241 242
		this._register(ViewsRegistry.onViewsRegistered(this.onViewsRegistered, this));
		this._register(ViewsRegistry.onViewsDeregistered(this.onViewsDeregistered, this));
		this._register(this.contextKeyService.onDidChangeContext(keys => this.onContextChanged(keys)));
243

244 245 246
		// Update headers after and title contributed views after available, since we read from cache in the beginning to know if the viewlet has single view or not. Ref #29609
		this.extensionService.onReady().then(() => {
			this.areExtensionsReady = true;
S
Sandeep Somavarapu 已提交
247
			this.updateHeaders();
248
		});
249

250
		this.onViewsRegistered(ViewsRegistry.getViews(this.location));
251
		this.focus();
S
Sandeep Somavarapu 已提交
252
	}
253

J
Joao 已提交
254
	getContextMenuActions(): IAction[] {
S
Sandeep Somavarapu 已提交
255
		return this.getViewDescriptorsFromRegistry(true)
S
Sandeep Somavarapu 已提交
256
			.filter(viewDescriptor => viewDescriptor.canToggleVisibility && this.contextKeyService.contextMatchesRules(viewDescriptor.when))
S
Sandeep Somavarapu 已提交
257 258 259 260
			.map(viewDescriptor => (<IAction>{
				id: `${viewDescriptor.id}.toggleVisibility`,
				label: viewDescriptor.name,
				checked: this.isCurrentlyVisible(viewDescriptor),
S
Sandeep Somavarapu 已提交
261
				enabled: true,
S
Sandeep Somavarapu 已提交
262 263
				run: () => this.toggleViewVisibility(viewDescriptor.id)
			}));
264 265
	}

J
Joao 已提交
266
	setVisible(visible: boolean): TPromise<void> {
267
		return super.setVisible(visible)
268
			.then(() => TPromise.join(this.viewsViewletPanels.filter(view => view.isVisible() !== visible)
269
				.map((view) => view.setVisible(visible))))
270 271 272
			.then(() => void 0);
	}

273 274
	layout(dimension: Dimension): void {
		super.layout(dimension);
J
Joao 已提交
275

J
Joao Moreno 已提交
276 277 278 279 280
		if (!this.didLayout) {
			this.didLayout = true;
			this._resizePanels();
		}

S
Sandeep Somavarapu 已提交
281
		this.updateAllViewsSizes();
282 283
	}

J
Joao 已提交
284
	getOptimalWidth(): number {
285
		const additionalMargin = 16;
286
		const optimalWidth = Math.max(...this.viewsViewletPanels.map(view => view.getOptimalWidth() || 0));
287 288 289
		return optimalWidth + additionalMargin;
	}

J
Joao 已提交
290
	shutdown(): void {
291
		this.viewsViewletPanels.forEach((view) => view.shutdown());
292 293 294
		super.shutdown();
	}

J
Joao Moreno 已提交
295
	toggleViewVisibility(id: string, visible?: boolean): void {
S
Sandeep Somavarapu 已提交
296 297
		const view = this.getView(id);
		let viewState = this.viewsStates.get(id);
J
Joao Moreno 已提交
298 299 300 301 302

		if ((visible === true && view) || (visible === false && !view)) {
			return;
		}

303 304 305 306
		if (view) {
			viewState = viewState || this.createViewState(view);
			viewState.isHidden = true;
		} else {
307
			viewState = viewState || { collapsed: true, size: void 0, isHidden: false, order: void 0 };
308 309
			viewState.isHidden = false;
		}
S
Sandeep Somavarapu 已提交
310
		this.viewsStates.set(id, viewState);
311 312 313
		this.updateViews();
	}

314
	private onViewsRegistered(views: IViewDescriptor[]): TPromise<ViewsViewletPanel[]> {
315 316 317 318 319 320 321 322
		this.viewsContextKeys.clear();
		for (const viewDescriptor of this.getViewDescriptorsFromRegistry()) {
			if (viewDescriptor.when) {
				for (const key of viewDescriptor.when.keys()) {
					this.viewsContextKeys.add(key);
				}
			}
		}
323

324 325 326
		return this.updateViews();
	}

327
	private onViewsDeregistered(views: IViewDescriptor[]): TPromise<ViewsViewletPanel[]> {
328 329 330
		return this.updateViews(views);
	}

331
	private onContextChanged(keys: string[]): void {
332 333 334 335
		if (!keys) {
			return;
		}

336 337 338 339 340 341 342 343 344 345 346
		let hasToUpdate: boolean = false;
		for (const key of keys) {
			if (this.viewsContextKeys.has(key)) {
				hasToUpdate = true;
				break;
			}
		}

		if (hasToUpdate) {
			this.updateViews();
		}
S
#27823  
Sandeep Somavarapu 已提交
347 348
	}

349 350 351 352 353
	protected updateViews(unregisteredViews: IViewDescriptor[] = []): TPromise<ViewsViewletPanel[]> {
		const registeredViews = this.getViewDescriptorsFromRegistry();
		const [visible, toAdd, toRemove] = registeredViews.reduce<[IViewDescriptor[], IViewDescriptor[], IViewDescriptor[]]>((result, viewDescriptor) => {
			const isCurrentlyVisible = this.isCurrentlyVisible(viewDescriptor);
			const canBeVisible = this.canBeVisible(viewDescriptor);
354

355 356 357
			if (canBeVisible) {
				result[0].push(viewDescriptor);
			}
358

359 360 361
			if (!isCurrentlyVisible && canBeVisible) {
				result[1].push(viewDescriptor);
			}
362

363 364 365
			if (isCurrentlyVisible && !canBeVisible) {
				result[2].push(viewDescriptor);
			}
366

367
			return result;
368

369
		}, [[], [], unregisteredViews]);
370

371
		const toCreate: ViewsViewletPanel[] = [];
372

373
		if (toAdd.length || toRemove.length) {
374 375 376
			const panels = [...this.viewsViewletPanels];

			for (const view of panels) {
377
				let viewState = this.viewsStates.get(view.id);
378
				if (!viewState || typeof viewState.size === 'undefined' || !view.isExpanded() !== viewState.collapsed) {
379 380
					viewState = this.updateViewStateSize(view);
					this.viewsStates.set(view.id, viewState);
381
				}
382
			}
S
#27823  
Sandeep Somavarapu 已提交
383

384 385 386
			if (toRemove.length) {
				for (const viewDescriptor of toRemove) {
					let view = this.getView(viewDescriptor.id);
387 388
					const viewState = this.updateViewStateSize(view);
					this.viewsStates.set(view.id, viewState);
389
					this.removePanel(view);
390
					this.viewsViewletPanels.splice(this.viewsViewletPanels.indexOf(view), 1);
S
Sandeep Somavarapu 已提交
391
				}
392
			}
S
Sandeep Somavarapu 已提交
393

394 395 396 397 398 399 400 401
			for (const viewDescriptor of toAdd) {
				let viewState = this.viewsStates.get(viewDescriptor.id);
				let index = visible.indexOf(viewDescriptor);
				const view = this.createView(viewDescriptor,
					{
						id: viewDescriptor.id,
						name: viewDescriptor.name,
						actionRunner: this.getActionRunner(),
S
Sandeep Somavarapu 已提交
402
						expanded: !(viewState ? viewState.collapsed : viewDescriptor.collapsed),
403 404 405 406
						viewletSettings: this.viewletSettings
					});
				toCreate.push(view);

J
Joao Moreno 已提交
407
				const size = (viewState && viewState.size) || viewDescriptor.size || 200;
408
				this.addPanel(view, size, index);
409
				this.viewsViewletPanels.splice(index, 0, view);
S
Sandeep Somavarapu 已提交
410 411

				this.viewsStates.set(view.id, this.updateViewStateSize(view));
412
			}
413 414 415

			return TPromise.join(toCreate.map(view => view.create()))
				.then(() => this.onViewsUpdated())
J
Joao Moreno 已提交
416
				.then(() => this._resizePanels())
417
				.then(() => toCreate);
418
		}
419

420
		return TPromise.as([]);
421 422
	}

S
Sandeep Somavarapu 已提交
423 424 425 426 427 428 429
	private updateAllViewsSizes(): void {
		for (const view of this.viewsViewletPanels) {
			let viewState = this.updateViewStateSize(view);
			this.viewsStates.set(view.id, viewState);
		}
	}

J
Joao Moreno 已提交
430
	private _resizePanels(): void {
J
Joao Moreno 已提交
431 432 433 434
		if (!this.didLayout) {
			return;
		}

J
Joao Moreno 已提交
435 436 437 438 439 440 441
		for (const panel of this.viewsViewletPanels) {
			const viewState = this.viewsStates.get(panel.id);
			const size = (viewState && viewState.size) || 200;
			this.resizePanel(panel, size);
		}
	}

J
Joao Moreno 已提交
442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459
	movePanel(from: ViewletPanel, to: ViewletPanel): void {
		const fromIndex = firstIndex(this.viewsViewletPanels, panel => panel === from);
		const toIndex = firstIndex(this.viewsViewletPanels, panel => panel === to);

		if (fromIndex < 0 || fromIndex >= this.viewsViewletPanels.length) {
			return;
		}

		if (toIndex < 0 || toIndex >= this.viewsViewletPanels.length) {
			return;
		}

		super.movePanel(from, to);

		const [panel] = this.viewsViewletPanels.splice(fromIndex, 1);
		this.viewsViewletPanels.splice(toIndex, 0, panel);

		for (let order = 0; order < this.viewsViewletPanels.length; order++) {
J
Joao Moreno 已提交
460 461 462 463 464 465 466
			const view = this.viewsStates.get(this.viewsViewletPanels[order].id);

			if (!view) {
				continue;
			}

			view.order = order;
J
Joao Moreno 已提交
467 468 469
		}
	}

J
Joao Moreno 已提交
470 471 472 473
	protected getDefaultViewSize(): number | undefined {
		return undefined;
	}

474 475 476 477
	private isCurrentlyVisible(viewDescriptor: IViewDescriptor): boolean {
		return !!this.getView(viewDescriptor.id);
	}

478
	private canBeVisible(viewDescriptor: IViewDescriptor): boolean {
479
		const viewstate = this.viewsStates.get(viewDescriptor.id);
J
Joao Moreno 已提交
480
		if (viewstate && viewstate.isHidden) {
481 482
			return false;
		}
483 484 485
		return this.contextKeyService.contextMatchesRules(viewDescriptor.when);
	}

S
#27823  
Sandeep Somavarapu 已提交
486
	private onViewsUpdated(): TPromise<void> {
S
Sandeep Somavarapu 已提交
487
		this.viewHeaderContextMenuListeners = dispose(this.viewHeaderContextMenuListeners);
488

489
		for (const viewDescriptor of this.getViewDescriptorsFromRegistry()) {
S
Sandeep Somavarapu 已提交
490
			const view = this.getView(viewDescriptor.id);
491

S
Sandeep Somavarapu 已提交
492
			if (view) {
J
Joao Moreno 已提交
493
				this.viewHeaderContextMenuListeners.push(DOM.addDisposableListener(view.draggableElement, DOM.EventType.CONTEXT_MENU, e => {
494 495 496 497 498 499
					e.stopPropagation();
					e.preventDefault();
					if (viewDescriptor.canToggleVisibility) {
						this.onContextMenu(new StandardMouseEvent(e), view);
					}
				}));
S
Sandeep Somavarapu 已提交
500 501 502
			}
		}

S
#27823  
Sandeep Somavarapu 已提交
503 504 505
		return this.setVisible(this.isVisible());
	}

S
Sandeep Somavarapu 已提交
506 507 508 509 510 511 512
	private updateHeaders(): void {
		if (this.viewsViewletPanels.length) {
			this.updateTitleArea();
			this.updateViewHeaders();
		}
	}

513
	private onContextMenu(event: StandardMouseEvent, view: ViewsViewletPanel): void {
S
Sandeep Somavarapu 已提交
514 515 516 517 518 519
		event.stopPropagation();
		event.preventDefault();

		let anchor: { x: number, y: number } = { x: event.posx, y: event.posy };
		this.contextMenuService.showContextMenu({
			getAnchor: () => anchor,
S
Sandeep Somavarapu 已提交
520
			getActions: () => TPromise.as([<IAction>{
S
Sandeep Somavarapu 已提交
521
				id: `${view.id}.removeView`,
S
Sandeep Somavarapu 已提交
522
				label: nls.localize('hideView', "Hide from Side Bar"),
S
Sandeep Somavarapu 已提交
523 524 525 526 527 528
				enabled: true,
				run: () => this.toggleViewVisibility(view.id)
			}]),
		});
	}

529
	protected isSingleView(): boolean {
530 531 532
		if (!this.showHeaderInTitleWhenSingleView) {
			return false;
		}
S
Sandeep Somavarapu 已提交
533 534 535 536
		if (this.getViewDescriptorsFromRegistry().length === 0) {
			return false;
		}
		if (this.length > 1) {
S
Sandeep Somavarapu 已提交
537 538
			return false;
		}
S
Sandeep Somavarapu 已提交
539
		// Check in cache so that view do not jump. See #29609
S
Sandeep Somavarapu 已提交
540
		if (ViewLocation.getContributedViewLocation(this.location.id) && !this.areExtensionsReady) {
S
Sandeep Somavarapu 已提交
541
			let visibleViewsCount = 0;
S
Sandeep Somavarapu 已提交
542
			this.viewsStates.forEach((viewState, id) => {
543
				if (!viewState.isHidden) {
S
Sandeep Somavarapu 已提交
544 545 546 547
					visibleViewsCount++;
				}
			});
			return visibleViewsCount === 1;
S
Sandeep Somavarapu 已提交
548
		}
S
Sandeep Somavarapu 已提交
549
		return super.isSingleView();
S
Sandeep Somavarapu 已提交
550 551
	}

J
Joao Moreno 已提交
552
	protected getViewDescriptorsFromRegistry(defaultOrder: boolean = false): IViewDescriptor[] {
553 554
		return ViewsRegistry.getViews(this.location)
			.sort((a, b) => {
555 556 557 558
				const viewStateA = this.viewsStates.get(a.id);
				const viewStateB = this.viewsStates.get(b.id);
				const orderA = !defaultOrder && viewStateA ? viewStateA.order : a.order;
				const orderB = !defaultOrder && viewStateB ? viewStateB.order : b.order;
559 560

				if (orderB === void 0 || orderB === null) {
561
					return -1;
S
#27823  
Sandeep Somavarapu 已提交
562
				}
563
				if (orderA === void 0 || orderA === null) {
564
					return 1;
S
#27823  
Sandeep Somavarapu 已提交
565
				}
566

567
				return orderA - orderB;
568
			});
569 570
	}

571 572
	protected createView(viewDescriptor: IViewDescriptor, options: IViewletViewOptions): ViewsViewletPanel {
		return this.instantiationService.createInstance(viewDescriptor.ctor, options);
573 574
	}

575 576
	protected get views(): ViewsViewletPanel[] {
		return this.viewsViewletPanels;
S
Sandeep Somavarapu 已提交
577 578
	}

579 580
	protected getView(id: string): ViewsViewletPanel {
		return this.viewsViewletPanels.filter(view => view.id === id)[0];
581
	}
S
#27823  
Sandeep Somavarapu 已提交
582

583
	private updateViewStateSize(view: ViewsViewletPanel): IViewState {
584 585 586 587 588
		const currentState = this.viewsStates.get(view.id);
		const newViewState = this.createViewState(view);
		return currentState ? { ...currentState, collapsed: newViewState.collapsed, size: newViewState.size } : newViewState;
	}

589
	protected createViewState(view: ViewsViewletPanel): IViewState {
S
#27823  
Sandeep Somavarapu 已提交
590
		return {
591
			collapsed: !view.isExpanded(),
J
Joao Moreno 已提交
592
			size: this.getPanelSize(view),
593
			isHidden: false,
594
			order: this.viewsViewletPanels.indexOf(view)
S
#27823  
Sandeep Somavarapu 已提交
595 596
		};
	}
J
Joao Moreno 已提交
597 598 599 600 601 602 603 604 605 606 607 608 609
}

export class PersistentViewsViewlet extends ViewsViewlet {

	constructor(
		id: string,
		location: ViewLocation,
		private viewletStateStorageId: string,
		showHeaderInTitleWhenSingleView: boolean,
		@ITelemetryService telemetryService: ITelemetryService,
		@IStorageService storageService: IStorageService,
		@IInstantiationService instantiationService: IInstantiationService,
		@IThemeService themeService: IThemeService,
J
Joao 已提交
610
		@IWorkspaceContextService protected contextService: IWorkspaceContextService,
J
Joao Moreno 已提交
611 612 613 614
		@IContextKeyService contextKeyService: IContextKeyService,
		@IContextMenuService contextMenuService: IContextMenuService,
		@IExtensionService extensionService: IExtensionService
	) {
J
Joao 已提交
615
		super(id, location, showHeaderInTitleWhenSingleView, telemetryService, storageService, instantiationService, themeService, contextKeyService, contextMenuService, extensionService);
S
Sandeep Somavarapu 已提交
616 617 618
	}

	create(parent: Builder): TPromise<void> {
J
Joao Moreno 已提交
619
		this.loadViewsStates();
S
Sandeep Somavarapu 已提交
620
		return super.create(parent);
J
Joao Moreno 已提交
621 622 623 624 625 626 627
	}

	shutdown(): void {
		this.saveViewsStates();
		super.shutdown();
	}

S
Sandeep Somavarapu 已提交
628
	protected saveViewsStates(): void {
J
Joao Moreno 已提交
629 630 631 632
		const viewsStates = {};
		const registeredViewDescriptors = this.getViewDescriptorsFromRegistry();
		this.viewsStates.forEach((viewState, id) => {
			const view = this.getView(id);
J
Joao Moreno 已提交
633

J
Joao Moreno 已提交
634
			if (view) {
J
Joao Moreno 已提交
635
				viewsStates[id] = this.createViewState(view);
J
Joao Moreno 已提交
636 637 638 639 640 641 642 643
			} else {
				const viewDescriptor = registeredViewDescriptors.filter(v => v.id === id)[0];
				if (viewDescriptor) {
					viewsStates[id] = viewState;
				}
			}
		});

644
		this.storageService.store(this.viewletStateStorageId, JSON.stringify(viewsStates), this.contextService.getWorkbenchState() !== WorkbenchState.EMPTY ? StorageScope.WORKSPACE : StorageScope.GLOBAL);
J
Joao Moreno 已提交
645 646
	}

S
Sandeep Somavarapu 已提交
647
	protected loadViewsStates(): void {
648
		const viewsStates = JSON.parse(this.storageService.get(this.viewletStateStorageId, this.contextService.getWorkbenchState() !== WorkbenchState.EMPTY ? StorageScope.WORKSPACE : StorageScope.GLOBAL, '{}'));
J
Joao Moreno 已提交
649 650
		Object.keys(viewsStates).forEach(id => this.viewsStates.set(id, <IViewState>viewsStates[id]));
	}
651
}