workbench.ts 45.2 KB
Newer Older
E
Erich Gamma 已提交
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.
 *--------------------------------------------------------------------------------------------*/

'use strict';

import 'vs/css!./media/workbench';
9

10
import { localize } from 'vs/nls';
J
Johannes Rieken 已提交
11 12
import { TPromise, ValueCallback } from 'vs/base/common/winjs.base';
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
13
import Event, { Emitter, chain } from 'vs/base/common/event';
E
Erich Gamma 已提交
14
import DOM = require('vs/base/browser/dom');
B
Benjamin Pasero 已提交
15
import { Builder, $ } from 'vs/base/browser/builder';
J
Johannes Rieken 已提交
16
import { Delayer } from 'vs/base/common/async';
17
import * as browser from 'vs/base/browser/browser';
E
Erich Gamma 已提交
18
import assert = require('vs/base/common/assert');
19
import { StopWatch } from 'vs/base/common/stopwatch';
20
import { startTimer } from 'vs/base/node/startupTimers';
E
Erich Gamma 已提交
21
import errors = require('vs/base/common/errors');
22
import { BackupFileService } from 'vs/workbench/services/backup/node/backupFileService';
23
import { IBackupFileService } from 'vs/workbench/services/backup/common/backup';
J
Johannes Rieken 已提交
24 25
import { toErrorMessage } from 'vs/base/common/errorMessage';
import { Registry } from 'vs/platform/platform';
B
Benjamin Pasero 已提交
26
import { isWindows, isLinux, isMacintosh } from 'vs/base/common/platform';
J
Johannes Rieken 已提交
27
import { IOptions } from 'vs/workbench/common/options';
28
import { Position as EditorPosition, IResourceDiffInput, IUntitledResourceInput, IEditor } from 'vs/platform/editor/common/editor';
J
Johannes Rieken 已提交
29
import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions';
30
import { IEditorRegistry, Extensions as EditorExtensions } from 'vs/workbench/common/editor';
J
Johannes Rieken 已提交
31 32 33 34 35 36
import { HistoryService } from 'vs/workbench/services/history/browser/history';
import { ActivitybarPart } from 'vs/workbench/browser/parts/activitybar/activitybarPart';
import { EditorPart } from 'vs/workbench/browser/parts/editor/editorPart';
import { SidebarPart } from 'vs/workbench/browser/parts/sidebar/sidebarPart';
import { PanelPart } from 'vs/workbench/browser/parts/panel/panelPart';
import { StatusbarPart } from 'vs/workbench/browser/parts/statusbar/statusbarPart';
B
Benjamin Pasero 已提交
37 38
import { TitlebarPart } from 'vs/workbench/browser/parts/titlebar/titlebarPart';
import { WorkbenchLayout } from 'vs/workbench/browser/layout';
39
import { IActionBarRegistry, Extensions as ActionBarExtensions } from 'vs/workbench/browser/actions';
J
Johannes Rieken 已提交
40 41 42 43
import { PanelRegistry, Extensions as PanelExtensions } from 'vs/workbench/browser/panel';
import { QuickOpenController } from 'vs/workbench/browser/parts/quickopen/quickOpenController';
import { getServices } from 'vs/platform/instantiation/common/extensions';
import { WorkbenchEditorService } from 'vs/workbench/services/editor/browser/editorService';
I
isidor 已提交
44
import { Position, Parts, IPartService, ILayoutOptions } from 'vs/workbench/services/part/common/partService';
45
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
J
Johannes Rieken 已提交
46 47 48 49
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
import { ContextMenuService } from 'vs/workbench/services/contextview/electron-browser/contextmenuService';
import { WorkbenchKeybindingService } from 'vs/workbench/services/keybinding/electron-browser/keybindingService';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
50
import { WorkspaceConfigurationService } from 'vs/workbench/services/configuration/node/configuration';
J
Johannes Rieken 已提交
51 52 53 54
import { IConfigurationEditingService } from 'vs/workbench/services/configuration/common/configurationEditing';
import { ConfigurationEditingService } from 'vs/workbench/services/configuration/node/configurationEditingService';
import { ContextKeyService } from 'vs/platform/contextkey/browser/contextKeyService';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
55
import { IKeybindingEditingService, KeybindingsEditingService } from 'vs/workbench/services/keybinding/common/keybindingEditing';
J
Johannes Rieken 已提交
56
import { ContextKeyExpr, RawContextKey, IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey';
57
import { IActivityBarService } from 'vs/workbench/services/activity/common/activityBarService';
B
Benjamin Pasero 已提交
58
import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet';
P
Pine Wu 已提交
59
import { ViewletService } from 'vs/workbench/services/viewlet/browser/viewletService';
J
Johannes Rieken 已提交
60 61
import { FileService } from 'vs/workbench/services/files/electron-browser/fileService';
import { IFileService } from 'vs/platform/files/common/files';
62
import { IListService, ListService } from 'vs/platform/list/browser/listService';
J
Johannes Rieken 已提交
63 64 65
import { IConfigurationResolverService } from 'vs/workbench/services/configurationResolver/common/configurationResolver';
import { ConfigurationResolverService } from 'vs/workbench/services/configurationResolver/node/configurationResolverService';
import { IPanelService } from 'vs/workbench/services/panel/common/panelService';
B
Benjamin Pasero 已提交
66
import { ITitleService } from 'vs/workbench/services/title/common/titleService';
J
Johannes Rieken 已提交
67
import { WorkbenchMessageService } from 'vs/workbench/services/message/browser/messageService';
68
import { IWorkbenchEditorService, IResourceInputType } from 'vs/workbench/services/editor/common/editorService';
J
Johannes Rieken 已提交
69
import { IQuickOpenService } from 'vs/platform/quickOpen/common/quickOpen';
70 71
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
import { ClipboardService } from 'vs/platform/clipboard/electron-browser/clipboardService';
J
Johannes Rieken 已提交
72 73 74 75 76 77
import { IEditorGroupService } from 'vs/workbench/services/group/common/groupService';
import { IHistoryService } from 'vs/workbench/services/history/common/history';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
import { TextFileService } from 'vs/workbench/services/textfile/electron-browser/textFileService';
import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
J
Joao Moreno 已提交
78 79
import { ISCMService } from 'vs/workbench/services/scm/common/scm';
import { SCMService } from 'vs/workbench/services/scm/common/scmService';
80 81
import { IProgressService2 } from 'vs/platform/progress/common/progress';
import { ProgressService2 } from 'vs/workbench/services/progress/browser/progressService2';
82
import { TextModelResolverService } from 'vs/workbench/services/textmodelResolver/common/textModelResolverService';
83
import { ITextModelResolverService } from 'vs/editor/common/services/resolverService';
J
Johannes Rieken 已提交
84
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
85
import { ILifecycleService, ShutdownReason } from 'vs/platform/lifecycle/common/lifecycle';
86
import { IWindowService, IWindowConfiguration as IWindowSettings, IWindowConfiguration } from 'vs/platform/windows/common/windows';
J
Johannes Rieken 已提交
87 88
import { IMessageService } from 'vs/platform/message/common/message';
import { IStatusbarService } from 'vs/platform/statusbar/common/statusbar';
89
import { IMenuService, SyncActionDescriptor } from 'vs/platform/actions/common/actions';
J
Johannes Rieken 已提交
90 91 92 93
import { MenuService } from 'vs/platform/actions/common/menuService';
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
94
import { IWorkbenchActionRegistry, Extensions } from 'vs/workbench/common/actionRegistry';
95
import { OpenRecentAction, ToggleDevToolsAction, ReloadWindowAction } from "vs/workbench/electron-browser/actions";
96 97
import { KeyMod } from 'vs/base/common/keyCodes';
import { KeyCode } from 'vs/editor/common/standalone/standaloneBase';
E
Erich Gamma 已提交
98

A
Alex Dima 已提交
99 100
export const MessagesVisibleContext = new RawContextKey<boolean>('globalMessageVisible', false);
export const EditorsVisibleContext = new RawContextKey<boolean>('editorIsOpen', false);
I
isidor 已提交
101
export const InZenModeContext = new RawContextKey<boolean>('inZenMode', false);
J
Johannes Rieken 已提交
102
export const NoEditorsVisibleContext: ContextKeyExpr = EditorsVisibleContext.toNegated();
A
Alex Dima 已提交
103

E
Erich Gamma 已提交
104 105
interface WorkbenchParams {
	options: IOptions;
106
	configuration: IWindowConfiguration;
107
	serviceCollection: ServiceCollection;
E
Erich Gamma 已提交
108 109
}

I
isidor 已提交
110 111 112
interface IZenModeSettings {
	fullScreen: boolean;
	hideTabs: boolean;
113
	hideActivityBar: boolean;
I
isidor 已提交
114
	hideStatusBar: boolean;
I
isidor 已提交
115
	restore: boolean;
I
isidor 已提交
116 117
}

118 119 120 121 122
export interface IWorkbenchStartedInfo {
	customKeybindingsCount: number;
	restoreViewletDuration: number;
	restoreEditorsDuration: number;
	pinnedViewlets: string[];
123 124
	restoredViewlet: string;
	restoredEditors: string[];
125 126
}

E
Erich Gamma 已提交
127 128
export interface IWorkbenchCallbacks {
	onServicesCreated?: () => void;
129
	onWorkbenchStarted?: (info: IWorkbenchStartedInfo) => void;
E
Erich Gamma 已提交
130 131
}

132 133
const Identifiers = {
	WORKBENCH_CONTAINER: 'workbench.main.container',
B
Benjamin Pasero 已提交
134
	TITLEBAR_PART: 'workbench.parts.titlebar',
135 136 137 138 139 140 141
	ACTIVITYBAR_PART: 'workbench.parts.activitybar',
	SIDEBAR_PART: 'workbench.parts.sidebar',
	PANEL_PART: 'workbench.parts.panel',
	EDITOR_PART: 'workbench.parts.editor',
	STATUSBAR_PART: 'workbench.parts.statusbar'
};

E
Erich Gamma 已提交
142
/**
B
Benjamin Pasero 已提交
143
 * The workbench creates and lays out all parts that make up the workbench.
E
Erich Gamma 已提交
144 145 146 147
 */
export class Workbench implements IPartService {

	private static sidebarHiddenSettingKey = 'workbench.sidebar.hidden';
148
	private static sidebarRestoreSettingKey = 'workbench.sidebar.restore';
I
isidor 已提交
149
	private static panelHiddenSettingKey = 'workbench.panel.hidden';
I
isidor 已提交
150
	private static zenModeActiveSettingKey = 'workbench.zenmode.active';
E
Erich Gamma 已提交
151

152
	private static sidebarPositionConfigurationKey = 'workbench.sideBar.location';
153
	private static statusbarVisibleConfigurationKey = 'workbench.statusBar.visible';
S
Sanders Lauture 已提交
154
	private static activityBarVisibleConfigurationKey = 'workbench.activityBar.visible';
155

156 157
	private _onTitleBarVisibilityChange: Emitter<void>;

158
	public _serviceBrand: any;
E
Erich Gamma 已提交
159

B
Benjamin Pasero 已提交
160
	private parent: HTMLElement;
E
Erich Gamma 已提交
161 162 163 164 165 166 167
	private container: HTMLElement;
	private workbenchParams: WorkbenchParams;
	private workbenchContainer: Builder;
	private workbench: Builder;
	private workbenchStarted: boolean;
	private workbenchCreated: boolean;
	private workbenchShutdown: boolean;
168
	private editorService: WorkbenchEditorService;
P
Pine Wu 已提交
169
	private viewletService: IViewletService;
170
	private contextKeyService: IContextKeyService;
171
	private keybindingService: IKeybindingService;
172
	private backupFileService: IBackupFileService;
173
	private configurationEditingService: IConfigurationEditingService;
B
Benjamin Pasero 已提交
174
	private titlebarPart: TitlebarPart;
E
Erich Gamma 已提交
175 176
	private activitybarPart: ActivitybarPart;
	private sidebarPart: SidebarPart;
I
isidor 已提交
177
	private panelPart: PanelPart;
E
Erich Gamma 已提交
178 179 180 181 182 183 184 185 186 187
	private editorPart: EditorPart;
	private statusbarPart: StatusbarPart;
	private quickOpen: QuickOpenController;
	private workbenchLayout: WorkbenchLayout;
	private toDispose: IDisposable[];
	private toShutdown: { shutdown: () => void; }[];
	private callbacks: IWorkbenchCallbacks;
	private creationPromise: TPromise<boolean>;
	private creationPromiseComplete: ValueCallback;
	private sideBarHidden: boolean;
188
	private statusBarHidden: boolean;
S
Sanders Lauture 已提交
189
	private activityBarHidden: boolean;
E
Erich Gamma 已提交
190
	private sideBarPosition: Position;
I
isidor 已提交
191
	private panelHidden: boolean;
E
Erich Gamma 已提交
192
	private editorBackgroundDelayer: Delayer<void>;
A
Alex Dima 已提交
193 194
	private messagesVisibleContext: IContextKey<boolean>;
	private editorsVisibleContext: IContextKey<boolean>;
I
isidor 已提交
195
	private inZenMode: IContextKey<boolean>;
196
	private hasFilesToCreateOpenOrDiff: boolean;
I
isidor 已提交
197
	private zenMode: {
I
isidor 已提交
198 199
		active: boolean;
		transitionedToFullScreen: boolean;
200 201
		wasSideBarVisible: boolean;
		wasPanelVisible: boolean;
I
isidor 已提交
202
	};
E
Erich Gamma 已提交
203

204
	constructor(
B
Benjamin Pasero 已提交
205
		parent: HTMLElement,
206
		container: HTMLElement,
207
		configuration: IWindowConfiguration,
208 209
		options: IOptions,
		serviceCollection: ServiceCollection,
210
		@IInstantiationService private instantiationService: IInstantiationService,
211
		@IWorkspaceContextService private contextService: IWorkspaceContextService,
212 213 214
		@IStorageService private storageService: IStorageService,
		@ILifecycleService private lifecycleService: ILifecycleService,
		@IMessageService private messageService: IMessageService,
215
		@IConfigurationService private configurationService: WorkspaceConfigurationService,
216
		@ITelemetryService private telemetryService: ITelemetryService,
I
isidor 已提交
217 218
		@IEnvironmentService private environmentService: IEnvironmentService,
		@IWindowService private windowService: IWindowService
219
	) {
B
Benjamin Pasero 已提交
220
		this.parent = parent;
221
		this.container = container;
E
Erich Gamma 已提交
222 223

		this.workbenchParams = {
224
			options,
225
			configuration,
226
			serviceCollection
E
Erich Gamma 已提交
227 228
		};

229 230 231
		this.hasFilesToCreateOpenOrDiff =
			(options.filesToCreate && options.filesToCreate.length > 0) ||
			(options.filesToOpen && options.filesToOpen.length > 0) ||
232
			(options.filesToDiff && options.filesToDiff.length > 0);
233

E
Erich Gamma 已提交
234 235 236 237
		this.toDispose = [];
		this.toShutdown = [];
		this.editorBackgroundDelayer = new Delayer<void>(50);

238 239
		this._onTitleBarVisibilityChange = new Emitter<void>();

240
		this.creationPromise = new TPromise<boolean>(c => {
E
Erich Gamma 已提交
241 242 243 244
			this.creationPromiseComplete = c;
		});
	}

245 246 247 248
	public get onTitleBarVisibilityChange(): Event<void> {
		return this._onTitleBarVisibilityChange.event;
	}

249 250 251 252 253 254
	public get onEditorLayout(): Event<void> {
		return chain(this.editorPart.onLayout)
			.map(() => void 0)
			.event;
	}

E
Erich Gamma 已提交
255 256 257 258 259 260 261 262 263 264 265 266 267 268 269
	/**
	 * Starts the workbench and creates the HTML elements on the container. A workbench can only be started
	 * once. Use the shutdown function to free up resources created by the workbench on startup.
	 */
	public startup(callbacks?: IWorkbenchCallbacks): void {
		assert.ok(!this.workbenchStarted, 'Can not start a workbench that was already started');
		assert.ok(!this.workbenchShutdown, 'Can not start a workbench that was shutdown');

		try {
			this.workbenchStarted = true;
			this.callbacks = callbacks;

			// Create Workbench
			this.createWorkbench();

270 271 272
			// Install some global actions
			this.createGlobalActions();

E
Erich Gamma 已提交
273 274 275 276 277 278
			// Services
			this.initServices();
			if (this.callbacks && this.callbacks.onServicesCreated) {
				this.callbacks.onServicesCreated();
			}

279
			// Contexts
280 281
			this.messagesVisibleContext = MessagesVisibleContext.bindTo(this.contextKeyService);
			this.editorsVisibleContext = EditorsVisibleContext.bindTo(this.contextKeyService);
I
isidor 已提交
282
			this.inZenMode = InZenModeContext.bindTo(this.contextKeyService);
283

E
Erich Gamma 已提交
284 285 286 287 288 289 290 291 292 293 294 295
			// Register Listeners
			this.registerListeners();

			// Settings
			this.initSettings();

			// Create Workbench and Parts
			this.renderWorkbench();

			// Workbench Layout
			this.createWorkbenchLayout();

B
Benjamin Pasero 已提交
296
			// Load composites and editors in parallel
B
Benjamin Pasero 已提交
297
			const compositeAndEditorPromises: TPromise<any>[] = [];
E
Erich Gamma 已提交
298

P
Pine Wu 已提交
299
			// Restore last opened viewlet
300
			let viewletRestoreStopWatch: StopWatch;
301
			let viewletIdToRestore: string;
302
			if (!this.sideBarHidden) {
303

304
				if (this.shouldRestoreLastOpenedViewlet()) {
305
					viewletIdToRestore = this.storageService.get(SidebarPart.activeViewletSettingsKey, StorageScope.WORKSPACE);
B
polish  
Benjamin Pasero 已提交
306 307 308
				}

				if (!viewletIdToRestore) {
309
					viewletIdToRestore = this.viewletService.getDefaultViewletId();
P
Pine Wu 已提交
310
				}
311

312
				viewletRestoreStopWatch = StopWatch.create();
313 314
				const viewletTimer = startTimer('restore:viewlet');
				compositeAndEditorPromises.push(viewletTimer.while(this.viewletService.openViewlet(viewletIdToRestore)).then(() => {
315 316
					viewletRestoreStopWatch.stop();
				}));
E
Erich Gamma 已提交
317 318
			}

B
Benjamin Pasero 已提交
319
			// Load Panel
320
			const panelRegistry = Registry.as<PanelRegistry>(PanelExtensions.Panels);
321 322
			const panelId = this.storageService.get(PanelPart.activePanelSettingsKey, StorageScope.WORKSPACE, panelRegistry.getDefaultPanelId());
			if (!this.panelHidden && !!panelId) {
I
isidor 已提交
323
				compositeAndEditorPromises.push(this.panelPart.openPanel(panelId, false));
324 325
			}

B
Benjamin Pasero 已提交
326
			// Load Editors
327
			const editorRestoreStopWatch = StopWatch.create();
328
			const restoredEditors: string[] = [];
329 330
			const editorsTimer = startTimer('restore:editors');
			compositeAndEditorPromises.push(editorsTimer.while(this.resolveEditorsToOpen().then(inputs => {
331
				let editorOpenPromise: TPromise<IEditor[]>;
332 333
				if (inputs.length) {
					editorOpenPromise = this.editorService.openEditors(inputs.map(input => { return { input, position: EditorPosition.ONE }; }));
B
Benjamin Pasero 已提交
334
				} else {
B
Benjamin Pasero 已提交
335
					editorOpenPromise = this.editorPart.restoreEditors();
336
				}
337

338
				return editorOpenPromise.then(editors => {
339
					this.onEditorsChanged(); // make sure we show the proper background in the editor area
340
					editorRestoreStopWatch.stop();
341 342 343 344 345 346 347
					for (const editor of editors) {
						if (editor.input) {
							restoredEditors.push(editor.input.getName());
						} else {
							restoredEditors.push(`other:${editor.getId()}`);
						}
					}
E
Erich Gamma 已提交
348
				});
349
			})));
E
Erich Gamma 已提交
350

351
			if (this.storageService.getBoolean(Workbench.zenModeActiveSettingKey, StorageScope.WORKSPACE, false)) {
I
isidor 已提交
352 353 354
				this.toggleZenMode(true);
			}

E
Erich Gamma 已提交
355
			// Flag workbench as created once done
356
			const workbenchDone = (error?: Error) => {
E
Erich Gamma 已提交
357 358 359
				this.workbenchCreated = true;
				this.creationPromiseComplete(true);

B
Benjamin Pasero 已提交
360
				if (this.callbacks && this.callbacks.onWorkbenchStarted) {
361 362
					this.callbacks.onWorkbenchStarted({
						customKeybindingsCount: this.keybindingService.customKeybindingsCount(),
363 364
						restoreViewletDuration: viewletRestoreStopWatch ? Math.round(viewletRestoreStopWatch.elapsed()) : 0,
						restoreEditorsDuration: Math.round(editorRestoreStopWatch.elapsed()),
B
Benjamin Pasero 已提交
365
						pinnedViewlets: this.activitybarPart.getPinned(),
366 367
						restoredViewlet: viewletIdToRestore,
						restoredEditors
368
					});
B
Benjamin Pasero 已提交
369
				}
370 371 372 373 374 375

				if (error) {
					errors.onUnexpectedError(error);
				}
			};

B
polish  
Benjamin Pasero 已提交
376
			// Join viewlet, panel and editor promises
377
			TPromise.join(compositeAndEditorPromises).then(() => workbenchDone(), error => workbenchDone(error));
E
Erich Gamma 已提交
378 379 380
		} catch (error) {

			// Print out error
381
			console.error(toErrorMessage(error, true));
E
Erich Gamma 已提交
382 383 384 385 386 387

			// Rethrow
			throw error;
		}
	}

388
	private createGlobalActions(): void {
B
Benjamin Pasero 已提交
389
		const isDeveloping = !this.environmentService.isBuilt || this.environmentService.isExtensionDevelopment;
390

B
Benjamin Pasero 已提交
391
		// Actions registered here to adjust for developing vs built workbench
392 393
		const workbenchActionsRegistry = Registry.as<IWorkbenchActionRegistry>(Extensions.WorkbenchActions);
		workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(ReloadWindowAction, ReloadWindowAction.ID, ReloadWindowAction.LABEL, isDeveloping ? { primary: KeyMod.CtrlCmd | KeyCode.KEY_R } : void 0), 'Reload Window');
B
Benjamin Pasero 已提交
394
		workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(ToggleDevToolsAction, ToggleDevToolsAction.ID, ToggleDevToolsAction.LABEL, isDeveloping ? { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_I, mac: { primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.KEY_I } } : void 0), 'Developer: Toggle Developer Tools', localize('developer', "Developer"));
B
Benjamin Pasero 已提交
395
		workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(OpenRecentAction, OpenRecentAction.ID, OpenRecentAction.LABEL, { primary: isDeveloping ? null : KeyMod.CtrlCmd | KeyCode.KEY_R, mac: { primary: KeyMod.WinCtrl | KeyCode.KEY_R } }), 'File: Open Recent...', localize('file', "File"));
396 397
	}

398
	private resolveEditorsToOpen(): TPromise<IResourceInputType[]> {
B
Benjamin Pasero 已提交
399 400

		// Files to open, diff or create
401 402
		if (this.hasFilesToCreateOpenOrDiff) {
			const wbopt = this.workbenchParams.options;
B
Benjamin Pasero 已提交
403 404 405
			const filesToCreate = wbopt.filesToCreate || [];
			const filesToOpen = wbopt.filesToOpen || [];
			const filesToDiff = wbopt.filesToDiff;
B
Benjamin Pasero 已提交
406 407

			// Files to diff is exclusive
408
			if (filesToDiff && filesToDiff.length === 2) {
409 410 411 412 413
				return TPromise.as([<IResourceDiffInput>{
					leftResource: filesToDiff[0].resource,
					rightResource: filesToDiff[1].resource,
					options: { pinned: true }
				}]);
B
Benjamin Pasero 已提交
414 415 416 417
			}

			// Otherwise: Open/Create files
			else {
418 419 420
				const filesToCreateInputs: IUntitledResourceInput[] = filesToCreate.map(resourceInput => {
					return <IUntitledResourceInput>{
						filePath: resourceInput.resource.fsPath,
421 422
						options: { pinned: true }
					};
B
Benjamin Pasero 已提交
423
				});
424

425
				return TPromise.as([].concat(filesToOpen).concat(filesToCreateInputs));
B
Benjamin Pasero 已提交
426 427 428
			}
		}

429
		// Empty workbench: some first time users will not have an untiled file; returning users will always have one
430
		else if (!this.contextService.hasWorkspace() && this.telemetryService.getExperiments().openUntitledFile && !this.configurationService.lookup('workbench.welcome.enabled').value) {
431 432 433 434
			if (this.editorPart.hasEditorsToRestore()) {
				return TPromise.as([]); // do not open any empty untitled file if we have editors to restore
			}

435 436 437 438 439
			return this.backupFileService.hasBackups().then(hasBackups => {
				if (hasBackups) {
					return TPromise.as([]); // do not open any empty untitled file if we have backups to restore
				}

440
				return TPromise.as([<IUntitledResourceInput>{}]);
441
			});
B
Benjamin Pasero 已提交
442 443 444 445 446
		}

		return TPromise.as([]);
	}

E
Erich Gamma 已提交
447
	private initServices(): void {
B
Benjamin Pasero 已提交
448
		const { serviceCollection } = this.workbenchParams;
449

450
		this.toDispose.push(this.lifecycleService.onShutdown(this.shutdownComponents, this));
E
Erich Gamma 已提交
451 452

		// Services we contribute
453
		serviceCollection.set(IPartService, this);
E
Erich Gamma 已提交
454

455 456 457
		// Clipboard
		serviceCollection.set(IClipboardService, new ClipboardService());

458 459 460 461 462 463
		// Status bar
		this.statusbarPart = this.instantiationService.createInstance(StatusbarPart, Identifiers.STATUSBAR_PART);
		this.toDispose.push(this.statusbarPart);
		this.toShutdown.push(this.statusbarPart);
		serviceCollection.set(IStatusbarService, this.statusbarPart);

464 465 466
		// Progress 2
		serviceCollection.set(IProgressService2, new SyncDescriptor(ProgressService2));

467
		// Keybindings
A
Alex Dima 已提交
468
		this.contextKeyService = this.instantiationService.createInstance(ContextKeyService);
469
		serviceCollection.set(IContextKeyService, this.contextKeyService);
470

B
Benjamin Pasero 已提交
471
		this.keybindingService = this.instantiationService.createInstance(WorkbenchKeybindingService, window);
472
		serviceCollection.set(IKeybindingService, this.keybindingService);
A
Alex Dima 已提交
473

474 475 476
		// List
		serviceCollection.set(IListService, this.instantiationService.createInstance(ListService));

477
		// Context Menu
478
		serviceCollection.set(IContextMenuService, new SyncDescriptor(ContextMenuService));
479

480 481
		// Menus/Actions
		serviceCollection.set(IMenuService, new SyncDescriptor(MenuService));
482

P
Pine Wu 已提交
483
		// Sidebar part
484
		this.sidebarPart = this.instantiationService.createInstance(SidebarPart, Identifiers.SIDEBAR_PART);
E
Erich Gamma 已提交
485 486
		this.toDispose.push(this.sidebarPart);
		this.toShutdown.push(this.sidebarPart);
P
Pine Wu 已提交
487 488 489 490

		// Viewlet service
		this.viewletService = this.instantiationService.createInstance(ViewletService, this.sidebarPart);
		serviceCollection.set(IViewletService, this.viewletService);
E
Erich Gamma 已提交
491

I
isidor 已提交
492
		// Panel service (panel part)
493
		this.panelPart = this.instantiationService.createInstance(PanelPart, Identifiers.PANEL_PART);
I
isidor 已提交
494 495
		this.toDispose.push(this.panelPart);
		this.toShutdown.push(this.panelPart);
496
		serviceCollection.set(IPanelService, this.panelPart);
I
isidor 已提交
497

E
Erich Gamma 已提交
498
		// Activity service (activitybar part)
499
		this.activitybarPart = this.instantiationService.createInstance(ActivitybarPart, Identifiers.ACTIVITYBAR_PART);
E
Erich Gamma 已提交
500 501
		this.toDispose.push(this.activitybarPart);
		this.toShutdown.push(this.activitybarPart);
502
		serviceCollection.set(IActivityBarService, this.activitybarPart);
E
Erich Gamma 已提交
503 504

		// Editor service (editor part)
505
		this.editorPart = this.instantiationService.createInstance(EditorPart, Identifiers.EDITOR_PART, !this.hasFilesToCreateOpenOrDiff);
E
Erich Gamma 已提交
506 507
		this.toDispose.push(this.editorPart);
		this.toShutdown.push(this.editorPart);
508
		this.editorService = this.instantiationService.createInstance(WorkbenchEditorService, this.editorPart);
509
		serviceCollection.set(IWorkbenchEditorService, this.editorService);
510
		serviceCollection.set(IEditorGroupService, this.editorPart);
E
Erich Gamma 已提交
511

512 513 514 515 516 517
		// Title bar
		this.titlebarPart = this.instantiationService.createInstance(TitlebarPart, Identifiers.TITLEBAR_PART);
		this.toDispose.push(this.titlebarPart);
		this.toShutdown.push(this.titlebarPart);
		serviceCollection.set(ITitleService, this.titlebarPart);

518
		// File Service
519 520 521
		const fileService = this.instantiationService.createInstance(FileService);
		serviceCollection.set(IFileService, fileService);
		this.toDispose.push(fileService.onFileChanges(e => this.configurationService.handleWorkspaceFileEvents(e)));
522

523
		// History
524
		serviceCollection.set(IHistoryService, new SyncDescriptor(HistoryService));
525

526
		// Backup File Service
527
		this.backupFileService = this.instantiationService.createInstance(BackupFileService, this.workbenchParams.configuration.backupPath);
528
		serviceCollection.set(IBackupFileService, this.backupFileService);
529

530
		// Text File Service
531
		serviceCollection.set(ITextFileService, new SyncDescriptor(TextFileService));
532

J
Joao Moreno 已提交
533
		// SCM Service
534
		serviceCollection.set(ISCMService, new SyncDescriptor(SCMService));
535

B
Benjamin Pasero 已提交
536
		// Text Model Resolver Service
537
		serviceCollection.set(ITextModelResolverService, new SyncDescriptor(TextModelResolverService));
B
Benjamin Pasero 已提交
538

539
		// Configuration Editing
540 541
		this.configurationEditingService = this.instantiationService.createInstance(ConfigurationEditingService);
		serviceCollection.set(IConfigurationEditingService, this.configurationEditingService);
542

543 544 545
		// Keybinding Editing
		serviceCollection.set(IKeybindingEditingService, this.instantiationService.createInstance(KeybindingsEditingService));

546
		// Configuration Resolver
547
		const workspace = this.contextService.getWorkspace();
548
		serviceCollection.set(IConfigurationResolverService, new SyncDescriptor(ConfigurationResolverService, workspace ? workspace.resource : null, process.env));
549

E
Erich Gamma 已提交
550
		// Quick open service (quick open controller)
551
		this.quickOpen = this.instantiationService.createInstance(QuickOpenController);
E
Erich Gamma 已提交
552 553
		this.toDispose.push(this.quickOpen);
		this.toShutdown.push(this.quickOpen);
554
		serviceCollection.set(IQuickOpenService, this.quickOpen);
E
Erich Gamma 已提交
555

B
polish  
Benjamin Pasero 已提交
556
		// Contributed services
B
Benjamin Pasero 已提交
557
		const contributedServices = getServices();
E
Erich Gamma 已提交
558
		for (let contributedService of contributedServices) {
559
			serviceCollection.set(contributedService.id, contributedService.descriptor);
E
Erich Gamma 已提交
560 561 562
		}

		// Set the some services to registries that have been created eagerly
563 564 565
		Registry.as<IActionBarRegistry>(ActionBarExtensions.Actionbar).setInstantiationService(this.instantiationService);
		Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench).setInstantiationService(this.instantiationService);
		Registry.as<IEditorRegistry>(EditorExtensions.Editors).setInstantiationService(this.instantiationService);
E
Erich Gamma 已提交
566 567 568 569 570
	}

	private initSettings(): void {

		// Sidebar visibility
571
		this.sideBarHidden = this.storageService.getBoolean(Workbench.sidebarHiddenSettingKey, StorageScope.WORKSPACE, !this.contextService.hasWorkspace());
E
Erich Gamma 已提交
572

I
isidor 已提交
573
		// Panel part visibility
574
		const panelRegistry = Registry.as<PanelRegistry>(PanelExtensions.Panels);
B
Benjamin Pasero 已提交
575
		this.panelHidden = this.storageService.getBoolean(Workbench.panelHiddenSettingKey, StorageScope.WORKSPACE, true);
576 577
		if (!panelRegistry.getDefaultPanelId()) {
			this.panelHidden = true; // we hide panel part if there is no default panel
I
isidor 已提交
578
		}
I
isidor 已提交
579

E
Erich Gamma 已提交
580
		// Sidebar position
581 582
		const sideBarPosition = this.configurationService.lookup<string>(Workbench.sidebarPositionConfigurationKey).value;
		this.sideBarPosition = (sideBarPosition === 'right') ? Position.RIGHT : Position.LEFT;
B
Benjamin Pasero 已提交
583 584

		// Statusbar visibility
585 586
		const statusBarVisible = this.configurationService.lookup<string>(Workbench.statusbarVisibleConfigurationKey).value;
		this.statusBarHidden = !statusBarVisible;
S
Sanders Lauture 已提交
587 588 589 590

		// Activity bar visibility
		const activityBarVisible = this.configurationService.lookup<string>(Workbench.activityBarVisibleConfigurationKey).value;
		this.activityBarHidden = !activityBarVisible;
I
isidor 已提交
591

I
isidor 已提交
592 593
		// Zen mode
		this.zenMode = {
I
isidor 已提交
594
			active: false,
595 596 597
			transitionedToFullScreen: false,
			wasSideBarVisible: false,
			wasPanelVisible: false
I
isidor 已提交
598
		};
E
Erich Gamma 已提交
599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619
	}

	/**
	 * Returns whether the workbench has been started.
	 */
	public isStarted(): boolean {
		return this.workbenchStarted && !this.workbenchShutdown;
	}

	/**
	 * Returns whether the workbench has been fully created.
	 */
	public isCreated(): boolean {
		return this.workbenchCreated && this.workbenchStarted;
	}

	public joinCreation(): TPromise<boolean> {
		return this.creationPromise;
	}

	public hasFocus(part: Parts): boolean {
B
Benjamin Pasero 已提交
620
		const activeElement = document.activeElement;
E
Erich Gamma 已提交
621 622 623 624
		if (!activeElement) {
			return false;
		}

625 626 627 628 629
		const container = this.getContainer(part);
		return DOM.isAncestor(activeElement, container);
	}

	public getContainer(part: Parts): HTMLElement {
E
Erich Gamma 已提交
630 631
		let container: Builder = null;
		switch (part) {
B
Benjamin Pasero 已提交
632 633 634
			case Parts.TITLEBAR_PART:
				container = this.titlebarPart.getContainer();
				break;
E
Erich Gamma 已提交
635 636 637 638 639 640
			case Parts.ACTIVITYBAR_PART:
				container = this.activitybarPart.getContainer();
				break;
			case Parts.SIDEBAR_PART:
				container = this.sidebarPart.getContainer();
				break;
I
isidor 已提交
641 642 643
			case Parts.PANEL_PART:
				container = this.panelPart.getContainer();
				break;
E
Erich Gamma 已提交
644 645 646 647 648 649 650
			case Parts.EDITOR_PART:
				container = this.editorPart.getContainer();
				break;
			case Parts.STATUSBAR_PART:
				container = this.statusbarPart.getContainer();
				break;
		}
651
		return container && container.getHTMLElement();
E
Erich Gamma 已提交
652 653 654
	}

	public isVisible(part: Parts): boolean {
B
Benjamin Pasero 已提交
655
		switch (part) {
B
Benjamin Pasero 已提交
656
			case Parts.TITLEBAR_PART:
657
				return this.getCustomTitleBarStyle() && !browser.isFullscreen();
B
Benjamin Pasero 已提交
658
			case Parts.SIDEBAR_PART:
659
				return !this.sideBarHidden;
B
Benjamin Pasero 已提交
660
			case Parts.PANEL_PART:
661
				return !this.panelHidden;
B
Benjamin Pasero 已提交
662
			case Parts.STATUSBAR_PART:
663
				return !this.statusBarHidden;
S
Sanders Lauture 已提交
664
			case Parts.ACTIVITYBAR_PART:
665
				return !this.activityBarHidden;
666
		}
E
Erich Gamma 已提交
667 668 669 670

		return true; // any other part cannot be hidden
	}

671 672
	public getTitleBarOffset(): number {
		let offset = 0;
673
		if (this.isVisible(Parts.TITLEBAR_PART)) {
674 675 676 677 678 679
			offset = 22 / browser.getZoomFactor(); // adjust the position based on title bar size and zoom factor
		}

		return offset;
	}

680
	private getCustomTitleBarStyle(): 'custom' {
B
Benjamin Pasero 已提交
681
		if (!isMacintosh) {
682
			return null; // custom title bar is only supported on Mac currently
B
Benjamin Pasero 已提交
683 684
		}

685
		const isDev = !this.environmentService.isBuilt || this.environmentService.isExtensionDevelopment;
B
Benjamin Pasero 已提交
686
		if (isDev) {
687
			return null; // not enabled when developing due to https://github.com/electron/electron/issues/3647
B
Benjamin Pasero 已提交
688 689
		}

690
		const windowConfig = this.configurationService.getConfiguration<IWindowSettings>();
691 692 693 694 695
		if (windowConfig && windowConfig.window) {
			const useNativeTabs = windowConfig.window.nativeTabs;
			if (useNativeTabs) {
				return null; // native tabs on sierra do not work with custom title style
			}
B
Benjamin Pasero 已提交
696

697 698 699 700
			const style = windowConfig.window.titleBarStyle;
			if (style === 'custom') {
				return style;
			}
701 702 703
		}

		return null;
B
Benjamin Pasero 已提交
704 705
	}

706
	private setStatusBarHidden(hidden: boolean, skipLayout?: boolean): void {
707 708
		this.statusBarHidden = hidden;

I
isidor 已提交
709

710 711
		// Layout
		if (!skipLayout) {
712
			this.workbenchLayout.layout();
713 714 715
		}
	}

S
Sanders Lauture 已提交
716 717 718
	public setActivityBarHidden(hidden: boolean, skipLayout?: boolean): void {
		this.activityBarHidden = hidden;

I
isidor 已提交
719

S
Sanders Lauture 已提交
720 721
		// Layout
		if (!skipLayout) {
722
			this.workbenchLayout.layout();
S
Sanders Lauture 已提交
723 724 725
		}
	}

726
	public setSideBarHidden(hidden: boolean, skipLayout?: boolean): TPromise<void> {
E
Erich Gamma 已提交
727 728 729 730 731 732 733 734 735
		this.sideBarHidden = hidden;

		// Adjust CSS
		if (hidden) {
			this.workbench.addClass('nosidebar');
		} else {
			this.workbench.removeClass('nosidebar');
		}

736
		let promise = TPromise.as<any>(null);
B
Benjamin Pasero 已提交
737
		// If sidebar becomes hidden, also hide the current active Viewlet if any
E
Erich Gamma 已提交
738
		if (hidden && this.sidebarPart.getActiveViewlet()) {
739 740 741
			promise = this.sidebarPart.hideActiveViewlet().then(() => {
				const activeEditor = this.editorPart.getActiveEditor();
				const activePanel = this.panelPart.getActivePanel();
B
Benjamin Pasero 已提交
742

743 744 745 746 747 748 749
				// Pass Focus to Editor or Panel if Sidebar is now hidden
				if (this.hasFocus(Parts.PANEL_PART) && activePanel) {
					activePanel.focus();
				} else if (activeEditor) {
					activeEditor.focus();
				}
			});
E
Erich Gamma 已提交
750 751
		}

B
Benjamin Pasero 已提交
752
		// If sidebar becomes visible, show last active Viewlet or default viewlet
E
Erich Gamma 已提交
753
		else if (!hidden && !this.sidebarPart.getActiveViewlet()) {
754
			const viewletToOpen = this.sidebarPart.getLastActiveViewletId();
E
Erich Gamma 已提交
755
			if (viewletToOpen) {
756
				promise = this.sidebarPart.openViewlet(viewletToOpen, true);
E
Erich Gamma 已提交
757 758 759
			}
		}

760
		return promise.then(() => {
761

762
			// Remember in settings
763 764 765 766 767 768
			const defaultHidden = !this.contextService.hasWorkspace();
			if (hidden !== defaultHidden) {
				this.storageService.store(Workbench.sidebarHiddenSettingKey, hidden ? 'true' : 'false', StorageScope.WORKSPACE);
			} else {
				this.storageService.remove(Workbench.sidebarHiddenSettingKey, StorageScope.WORKSPACE);
			}
769 770 771

			// Layout
			if (!skipLayout) {
772
				this.workbenchLayout.layout();
773 774
			}
		});
E
Erich Gamma 已提交
775 776
	}

777
	public setPanelHidden(hidden: boolean, skipLayout?: boolean): TPromise<void> {
I
isidor 已提交
778
		this.panelHidden = hidden;
I
isidor 已提交
779

780 781 782 783 784 785 786
		// Adjust CSS
		if (hidden) {
			this.workbench.addClass('nopanel');
		} else {
			this.workbench.removeClass('nopanel');
		}

I
isidor 已提交
787
		// If panel part becomes hidden, also hide the current active panel if any
788
		let promise = TPromise.as<any>(null);
I
isidor 已提交
789
		if (hidden && this.panelPart.getActivePanel()) {
790 791 792 793 794 795 796
			promise = this.panelPart.hideActivePanel().then(() => {
				// Pass Focus to Editor if Panel part is now hidden
				const editor = this.editorPart.getActiveEditor();
				if (editor) {
					editor.focus();
				}
			});
I
isidor 已提交
797 798 799 800
		}

		// If panel part becomes visible, show last active panel or default panel
		else if (!hidden && !this.panelPart.getActivePanel()) {
801
			const panelToOpen = this.panelPart.getLastActivePanelId();
I
isidor 已提交
802
			if (panelToOpen) {
803
				promise = this.panelPart.openPanel(panelToOpen, true);
I
isidor 已提交
804 805 806
			}
		}

807
		return promise.then(() => {
808

809
			// Remember in settings
810 811 812 813 814
			if (!hidden) {
				this.storageService.store(Workbench.panelHiddenSettingKey, 'false', StorageScope.WORKSPACE);
			} else {
				this.storageService.remove(Workbench.panelHiddenSettingKey, StorageScope.WORKSPACE);
			}
815 816 817

			// Layout
			if (!skipLayout) {
818
				this.workbenchLayout.layout();
819 820
			}
		});
I
isidor 已提交
821 822
	}

I
isidor 已提交
823
	public toggleMaximizedPanel(): void {
824
		this.workbenchLayout.layout({ toggleMaximizedPanel: true });
I
isidor 已提交
825 826
	}

I
isidor 已提交
827 828 829 830
	public isPanelMaximized(): boolean {
		return this.workbenchLayout.isPanelMaximized();
	}

E
Erich Gamma 已提交
831 832 833 834
	public getSideBarPosition(): Position {
		return this.sideBarPosition;
	}

835
	private setSideBarPosition(position: Position): void {
E
Erich Gamma 已提交
836
		if (this.sideBarHidden) {
837
			this.setSideBarHidden(false, true /* Skip Layout */).done(undefined, errors.onUnexpectedError);
E
Erich Gamma 已提交
838 839
		}

B
Benjamin Pasero 已提交
840 841
		const newPositionValue = (position === Position.LEFT) ? 'left' : 'right';
		const oldPositionValue = (this.sideBarPosition === Position.LEFT) ? 'left' : 'right';
E
Erich Gamma 已提交
842 843 844 845 846 847 848 849
		this.sideBarPosition = position;

		// Adjust CSS
		this.activitybarPart.getContainer().removeClass(oldPositionValue);
		this.sidebarPart.getContainer().removeClass(oldPositionValue);
		this.activitybarPart.getContainer().addClass(newPositionValue);
		this.sidebarPart.getContainer().addClass(newPositionValue);

850 851 852 853
		// Update Styles
		this.activitybarPart.updateStyles();
		this.sidebarPart.updateStyles();

E
Erich Gamma 已提交
854
		// Layout
855
		this.workbenchLayout.layout();
E
Erich Gamma 已提交
856 857
	}

B
Benjamin Pasero 已提交
858
	public dispose(): void {
E
Erich Gamma 已提交
859
		if (this.isStarted()) {
B
Benjamin Pasero 已提交
860
			this.shutdownComponents();
E
Erich Gamma 已提交
861 862 863
			this.workbenchShutdown = true;
		}

J
Joao Moreno 已提交
864
		this.toDispose = dispose(this.toDispose);
E
Erich Gamma 已提交
865 866 867 868 869 870
	}

	/**
	 * Asks the workbench and all its UI components inside to lay out according to
	 * the containers dimension the workbench is living in.
	 */
B
Benjamin Pasero 已提交
871
	public layout(options?: ILayoutOptions): void {
E
Erich Gamma 已提交
872
		if (this.isStarted()) {
B
Benjamin Pasero 已提交
873
			this.workbenchLayout.layout(options);
E
Erich Gamma 已提交
874 875 876
		}
	}

877 878 879 880 881 882
	private shutdownComponents(reason = ShutdownReason.QUIT): void {

		// Restore sidebar if we are being shutdown as a matter of a reload
		if (reason === ShutdownReason.RELOAD) {
			this.storageService.store(Workbench.sidebarRestoreSettingKey, 'true', StorageScope.WORKSPACE);
		}
I
isidor 已提交
883

I
isidor 已提交
884
		// Preserve zen mode only on reload. Real quit gets out of zen mode so novice users do not get stuck in zen mode.
885 886 887 888 889 890 891
		const zenConfig = this.configurationService.getConfiguration<IZenModeSettings>('zenMode');
		const zenModeActive = (zenConfig.restore || reason === ShutdownReason.RELOAD) && this.zenMode.active;
		if (zenModeActive) {
			this.storageService.store(Workbench.zenModeActiveSettingKey, true, StorageScope.WORKSPACE);
		} else {
			this.storageService.remove(Workbench.zenModeActiveSettingKey, StorageScope.WORKSPACE);
		}
E
Erich Gamma 已提交
892 893 894 895 896 897 898 899

		// Pass shutdown on to each participant
		this.toShutdown.forEach(s => s.shutdown());
	}

	private registerListeners(): void {

		// Listen to editor changes
900
		this.toDispose.push(this.editorPart.onEditorsChanged(() => this.onEditorsChanged()));
901 902

		// Handle message service and quick open events
903 904
		this.toDispose.push((<WorkbenchMessageService>this.messageService).onMessagesShowing(() => this.messagesVisibleContext.set(true)));
		this.toDispose.push((<WorkbenchMessageService>this.messageService).onMessagesCleared(() => this.messagesVisibleContext.reset()));
905

906 907 908 909 910
		this.toDispose.push(this.quickOpen.onShow(() => (<WorkbenchMessageService>this.messageService).suspend())); // when quick open is open, don't show messages behind
		this.toDispose.push(this.quickOpen.onHide(() => (<WorkbenchMessageService>this.messageService).resume()));  // resume messages once quick open is closed again

		// Configuration changes
		this.toDispose.push(this.configurationService.onDidUpdateConfiguration(() => this.onDidUpdateConfiguration()));
911 912 913 914 915 916 917 918 919 920

		// Fullscreen changes
		this.toDispose.push(browser.onDidChangeFullscreen(() => this.onFullscreenChanged()));
	}

	private onFullscreenChanged(): void {
		if (!this.isCreated) {
			return; // we need to be ready
		}

921
		// Apply as CSS class
922 923 924 925 926
		const isFullscreen = browser.isFullscreen();
		if (isFullscreen) {
			this.addClass('fullscreen');
		} else {
			this.removeClass('fullscreen');
I
isidor 已提交
927 928
			if (this.zenMode.transitionedToFullScreen && this.zenMode.active) {
				this.toggleZenMode();
I
isidor 已提交
929
			}
930
		}
931

932 933 934 935 936
		// Changing fullscreen state of the window has an impact on custom title bar visibility, so we need to update
		const hasCustomTitle = this.getCustomTitleBarStyle() === 'custom';
		if (hasCustomTitle) {
			this._onTitleBarVisibilityChange.fire();
			this.layout(); // handle title bar when fullscreen changes
937
		}
E
Erich Gamma 已提交
938 939
	}

940
	private onEditorsChanged(): void {
B
Benjamin Pasero 已提交
941
		const visibleEditors = this.editorService.getVisibleEditors().length;
E
Erich Gamma 已提交
942 943 944 945

		// We update the editorpart class to indicate if an editor is opened or not
		// through a delay to accomodate for fast editor switching

946
		const editorContainer = this.editorPart.getContainer();
E
Erich Gamma 已提交
947
		if (visibleEditors === 0) {
948
			this.editorsVisibleContext.reset();
949
			this.editorBackgroundDelayer.trigger(() => editorContainer.addClass('empty'));
E
Erich Gamma 已提交
950
		} else {
951
			this.editorsVisibleContext.set(true);
952
			this.editorBackgroundDelayer.trigger(() => editorContainer.removeClass('empty'));
E
Erich Gamma 已提交
953 954 955
		}
	}

956
	private onDidUpdateConfiguration(skipLayout?: boolean): void {
957
		const newSidebarPositionValue = this.configurationService.lookup<string>(Workbench.sidebarPositionConfigurationKey).value;
958
		const newSidebarPosition = (newSidebarPositionValue === 'right') ? Position.RIGHT : Position.LEFT;
959 960 961
		if (newSidebarPosition !== this.getSideBarPosition()) {
			this.setSideBarPosition(newSidebarPosition);
		}
962

963 964 965 966 967
		if (!this.zenMode.active) {
			const newStatusbarHiddenValue = !this.configurationService.lookup<boolean>(Workbench.statusbarVisibleConfigurationKey).value;
			if (newStatusbarHiddenValue !== this.statusBarHidden) {
				this.setStatusBarHidden(newStatusbarHiddenValue, skipLayout);
			}
S
Sanders Lauture 已提交
968

969 970 971 972
			const newActivityBarHiddenValue = !this.configurationService.lookup<boolean>(Workbench.activityBarVisibleConfigurationKey).value;
			if (newActivityBarHiddenValue !== this.activityBarHidden) {
				this.setActivityBarHidden(newActivityBarHiddenValue, skipLayout);
			}
S
Sanders Lauture 已提交
973
		}
974 975
	}

E
Erich Gamma 已提交
976 977 978 979
	private createWorkbenchLayout(): void {
		this.workbenchLayout = this.instantiationService.createInstance(WorkbenchLayout,
			$(this.container),							// Parent
			this.workbench,								// Workbench Container
I
isidor 已提交
980
			{
B
Benjamin Pasero 已提交
981
				titlebar: this.titlebarPart,			// Title Bar
I
isidor 已提交
982 983 984 985 986 987
				activitybar: this.activitybarPart,		// Activity Bar
				editor: this.editorPart,				// Editor
				sidebar: this.sidebarPart,				// Sidebar
				panel: this.panelPart,					// Panel Part
				statusbar: this.statusbarPart,			// Statusbar
			},
B
Benjamin Pasero 已提交
988
			this.quickOpen								// Quickopen
E
Erich Gamma 已提交
989 990 991 992 993 994 995 996 997
		);

		this.toDispose.push(this.workbenchLayout);
	}

	private createWorkbench(): void {

		// Create Workbench DIV Off-DOM
		this.workbenchContainer = $('.monaco-workbench-container');
998
		this.workbench = $().div({ 'class': 'monaco-workbench ' + (isWindows ? 'windows' : isLinux ? 'linux' : 'mac'), id: Identifiers.WORKBENCH_CONTAINER }).appendTo(this.workbenchContainer);
E
Erich Gamma 已提交
999 1000 1001 1002 1003 1004 1005 1006
	}

	private renderWorkbench(): void {

		// Apply sidebar state as CSS class
		if (this.sideBarHidden) {
			this.workbench.addClass('nosidebar');
		}
1007 1008 1009
		if (this.panelHidden) {
			this.workbench.addClass('nopanel');
		}
E
Erich Gamma 已提交
1010

B
Benjamin Pasero 已提交
1011
		// Apply title style if shown
1012 1013 1014 1015 1016 1017 1018 1019
		const titleStyle = this.getCustomTitleBarStyle();
		if (titleStyle) {
			DOM.addClass(this.parent, `titlebar-style-${titleStyle}`);
		}

		// Apply fullscreen state
		if (browser.isFullscreen()) {
			this.workbench.addClass('fullscreen');
B
Benjamin Pasero 已提交
1020 1021
		}

E
Erich Gamma 已提交
1022
		// Create Parts
B
Benjamin Pasero 已提交
1023
		this.createTitlebarPart();
E
Erich Gamma 已提交
1024 1025 1026
		this.createActivityBarPart();
		this.createSidebarPart();
		this.createEditorPart();
1027
		this.createPanelPart();
E
Erich Gamma 已提交
1028 1029 1030 1031 1032 1033
		this.createStatusbarPart();

		// Add Workbench to DOM
		this.workbenchContainer.build(this.container);
	}

B
Benjamin Pasero 已提交
1034 1035 1036 1037 1038 1039 1040 1041 1042 1043
	private createTitlebarPart(): void {
		const titlebarContainer = $(this.workbench).div({
			'class': ['part', 'titlebar'],
			id: Identifiers.TITLEBAR_PART,
			role: 'contentinfo'
		});

		this.titlebarPart.create(titlebarContainer);
	}

E
Erich Gamma 已提交
1044
	private createActivityBarPart(): void {
B
Benjamin Pasero 已提交
1045
		const activitybarPartContainer = $(this.workbench)
E
Erich Gamma 已提交
1046 1047
			.div({
				'class': ['part', 'activitybar', this.sideBarPosition === Position.LEFT ? 'left' : 'right'],
1048 1049
				id: Identifiers.ACTIVITYBAR_PART,
				role: 'navigation'
E
Erich Gamma 已提交
1050 1051 1052 1053 1054 1055
			});

		this.activitybarPart.create(activitybarPartContainer);
	}

	private createSidebarPart(): void {
B
Benjamin Pasero 已提交
1056
		const sidebarPartContainer = $(this.workbench)
E
Erich Gamma 已提交
1057 1058
			.div({
				'class': ['part', 'sidebar', this.sideBarPosition === Position.LEFT ? 'left' : 'right'],
1059 1060
				id: Identifiers.SIDEBAR_PART,
				role: 'complementary'
E
Erich Gamma 已提交
1061 1062 1063 1064 1065
			});

		this.sidebarPart.create(sidebarPartContainer);
	}

I
isidor 已提交
1066
	private createPanelPart(): void {
B
Benjamin Pasero 已提交
1067
		const panelPartContainer = $(this.workbench)
I
isidor 已提交
1068
			.div({
1069
				'class': ['part', 'panel'],
1070 1071
				id: Identifiers.PANEL_PART,
				role: 'complementary'
I
isidor 已提交
1072 1073 1074 1075 1076
			});

		this.panelPart.create(panelPartContainer);
	}

E
Erich Gamma 已提交
1077
	private createEditorPart(): void {
B
Benjamin Pasero 已提交
1078
		const editorContainer = $(this.workbench)
E
Erich Gamma 已提交
1079
			.div({
1080
				'class': ['part', 'editor', 'empty'],
1081 1082
				id: Identifiers.EDITOR_PART,
				role: 'main'
E
Erich Gamma 已提交
1083 1084 1085 1086 1087 1088
			});

		this.editorPart.create(editorContainer);
	}

	private createStatusbarPart(): void {
B
Benjamin Pasero 已提交
1089
		const statusbarContainer = $(this.workbench).div({
E
Erich Gamma 已提交
1090
			'class': ['part', 'statusbar'],
1091 1092
			id: Identifiers.STATUSBAR_PART,
			role: 'contentinfo'
E
Erich Gamma 已提交
1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109
		});

		this.statusbarPart.create(statusbarContainer);
	}

	public getEditorPart(): EditorPart {
		assert.ok(this.workbenchStarted, 'Workbench is not started. Call startup() first.');

		return this.editorPart;
	}

	public getSidebarPart(): SidebarPart {
		assert.ok(this.workbenchStarted, 'Workbench is not started. Call startup() first.');

		return this.sidebarPart;
	}

I
isidor 已提交
1110 1111 1112 1113 1114 1115
	public getPanelPart(): PanelPart {
		assert.ok(this.workbenchStarted, 'Workbench is not started. Call startup() first.');

		return this.panelPart;
	}

E
Erich Gamma 已提交
1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132
	public getInstantiationService(): IInstantiationService {
		assert.ok(this.workbenchStarted, 'Workbench is not started. Call startup() first.');

		return this.instantiationService;
	}

	public addClass(clazz: string): void {
		if (this.workbench) {
			this.workbench.addClass(clazz);
		}
	}

	public removeClass(clazz: string): void {
		if (this.workbench) {
			this.workbench.removeClass(clazz);
		}
	}
1133 1134 1135 1136

	public getWorkbenchElementId(): string {
		return Identifiers.WORKBENCH_CONTAINER;
	}
1137

I
isidor 已提交
1138
	public toggleZenMode(skipLayout?: boolean): void {
I
isidor 已提交
1139 1140
		this.zenMode.active = !this.zenMode.active;
		// Check if zen mode transitioned to full screen and if now we are out of zen mode -> we need to go out of full screen
1141
		let toggleFullScreen = false;
I
isidor 已提交
1142
		if (this.zenMode.active) {
I
isidor 已提交
1143 1144
			const config = this.configurationService.getConfiguration<IZenModeSettings>('zenMode');
			toggleFullScreen = !browser.isFullscreen() && config.fullScreen;
I
isidor 已提交
1145
			this.zenMode.transitionedToFullScreen = toggleFullScreen;
1146 1147
			this.zenMode.wasSideBarVisible = this.isVisible(Parts.SIDEBAR_PART);
			this.zenMode.wasPanelVisible = this.isVisible(Parts.PANEL_PART);
1148
			this.setPanelHidden(true, true).done(undefined, errors.onUnexpectedError);
1149
			this.setSideBarHidden(true, true).done(undefined, errors.onUnexpectedError);
I
isidor 已提交
1150

1151 1152 1153
			if (config.hideActivityBar) {
				this.setActivityBarHidden(true, true);
			}
I
isidor 已提交
1154
			if (config.hideStatusBar) {
I
isidor 已提交
1155 1156
				this.setStatusBarHidden(true, true);
			}
I
isidor 已提交
1157
			if (config.hideTabs) {
I
isidor 已提交
1158 1159
				this.editorPart.hideTabs(true);
			}
1160
		} else {
1161
			if (this.zenMode.wasPanelVisible) {
1162
				this.setPanelHidden(false, true).done(undefined, errors.onUnexpectedError);
1163
			}
1164
			if (this.zenMode.wasSideBarVisible) {
1165
				this.setSideBarHidden(false, true).done(undefined, errors.onUnexpectedError);
1166
			}
1167 1168
			// Status bar and activity bar visibility come from settings -> update their visibility.
			this.onDidUpdateConfiguration(true);
I
isidor 已提交
1169
			this.editorPart.hideTabs(false);
I
isidor 已提交
1170 1171 1172 1173
			const activeEditor = this.editorPart.getActiveEditor();
			if (activeEditor) {
				activeEditor.focus();
			}
1174
			toggleFullScreen = this.zenMode.transitionedToFullScreen && browser.isFullscreen();
I
isidor 已提交
1175
		}
1176
		this.inZenMode.set(this.zenMode.active);
I
isidor 已提交
1177

I
isidor 已提交
1178
		if (!skipLayout) {
1179
			this.layout();
I
isidor 已提交
1180
		}
1181 1182 1183
		if (toggleFullScreen) {
			this.windowService.toggleFullScreen().done(undefined, errors.onUnexpectedError);
		}
I
isidor 已提交
1184 1185
	}

1186 1187 1188 1189 1190 1191 1192 1193 1194 1195
	// Resize requested part along the main axis
	// layout will do all the math for us and adjusts the other Parts
	public resizePart(part: Parts, sizeChange: number): void {
		switch (part) {
			case Parts.SIDEBAR_PART:
			case Parts.PANEL_PART:
			case Parts.EDITOR_PART:
				this.workbenchLayout.resizePart(part, sizeChange);
				break;
			default:
B
Benjamin Pasero 已提交
1196
				return; // Cannot resize other parts
1197 1198 1199 1200
		}
	}


1201
	private shouldRestoreLastOpenedViewlet(): boolean {
1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212
		if (!this.environmentService.isBuilt) {
			return true; // always restore sidebar when we are in development mode
		}

		const restore = this.storageService.getBoolean(Workbench.sidebarRestoreSettingKey, StorageScope.WORKSPACE);
		if (restore) {
			this.storageService.remove(Workbench.sidebarRestoreSettingKey, StorageScope.WORKSPACE); // only support once
		}

		return restore;
	}
J
Johannes Rieken 已提交
1213
}