workbench.ts 49.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';
16
import { Delayer, RunOnceScheduler } 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
import { toErrorMessage } from 'vs/base/common/errorMessage';
25
import { Registry } from 'vs/platform/registry/common/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 { WorkspaceService } from 'vs/workbench/services/configuration/node/configuration';
J
Johannes Rieken 已提交
51 52
import { IConfigurationEditingService } from 'vs/workbench/services/configuration/common/configurationEditing';
import { ConfigurationEditingService } from 'vs/workbench/services/configuration/node/configurationEditingService';
53 54
import { IJSONEditingService } from 'vs/workbench/services/configuration/common/jsonEditing';
import { JSONEditingService } from 'vs/workbench/services/configuration/node/jsonEditingService';
J
Johannes Rieken 已提交
55 56
import { ContextKeyService } from 'vs/platform/contextkey/browser/contextKeyService';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
57
import { IKeybindingEditingService, KeybindingsEditingService } from 'vs/workbench/services/keybinding/common/keybindingEditing';
J
Johannes Rieken 已提交
58
import { ContextKeyExpr, RawContextKey, IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey';
59
import { IActivityBarService } from 'vs/workbench/services/activity/common/activityBarService';
B
Benjamin Pasero 已提交
60
import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet';
P
Pine Wu 已提交
61
import { ViewletService } from 'vs/workbench/services/viewlet/browser/viewletService';
J
Johannes Rieken 已提交
62 63
import { FileService } from 'vs/workbench/services/files/electron-browser/fileService';
import { IFileService } from 'vs/platform/files/common/files';
64
import { IListService, ListService } from 'vs/platform/list/browser/listService';
J
Johannes Rieken 已提交
65 66 67
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 已提交
68
import { ITitleService } from 'vs/workbench/services/title/common/titleService';
J
Johannes Rieken 已提交
69
import { WorkbenchMessageService } from 'vs/workbench/services/message/browser/messageService';
70
import { IWorkbenchEditorService, IResourceInputType } from 'vs/workbench/services/editor/common/editorService';
J
Johannes Rieken 已提交
71
import { IQuickOpenService } from 'vs/platform/quickOpen/common/quickOpen';
72 73
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
import { ClipboardService } from 'vs/platform/clipboard/electron-browser/clipboardService';
J
Johannes Rieken 已提交
74 75 76 77 78 79
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 已提交
80 81
import { ISCMService } from 'vs/workbench/services/scm/common/scm';
import { SCMService } from 'vs/workbench/services/scm/common/scmService';
82 83
import { IProgressService2 } from 'vs/platform/progress/common/progress';
import { ProgressService2 } from 'vs/workbench/services/progress/browser/progressService2';
84
import { TextModelResolverService } from 'vs/workbench/services/textmodelResolver/common/textModelResolverService';
85
import { ITextModelService } from 'vs/editor/common/services/resolverService';
J
Johannes Rieken 已提交
86
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
87
import { ILifecycleService, ShutdownReason } from 'vs/platform/lifecycle/common/lifecycle';
88
import { IWindowService, IWindowConfiguration as IWindowSettings, IWindowConfiguration } from 'vs/platform/windows/common/windows';
J
Johannes Rieken 已提交
89 90
import { IMessageService } from 'vs/platform/message/common/message';
import { IStatusbarService } from 'vs/platform/statusbar/common/statusbar';
91
import { IMenuService, SyncActionDescriptor } from 'vs/platform/actions/common/actions';
J
Johannes Rieken 已提交
92 93 94 95
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';
96
import { IWorkbenchActionRegistry, Extensions } from 'vs/workbench/common/actionRegistry';
97
import { OpenRecentAction, ToggleDevToolsAction, ReloadWindowAction, inRecentFilesPickerContextKey } from "vs/workbench/electron-browser/actions";
98
import { KeyMod, KeyCode } from 'vs/base/common/keyCodes';
B
Benjamin Pasero 已提交
99 100 101 102
import { KeybindingsRegistry } from 'vs/platform/keybinding/common/keybindingsRegistry';
import { getQuickNavigateHandler, inQuickOpenContext } from 'vs/workbench/browser/parts/quickopen/quickopen';
import { IWorkspaceEditingService } from 'vs/workbench/services/workspace/common/workspaceEditing';
import { WorkspaceEditingService } from 'vs/workbench/services/workspace/node/workspaceEditingService';
E
Erich Gamma 已提交
103

A
Alex Dima 已提交
104 105
export const MessagesVisibleContext = new RawContextKey<boolean>('globalMessageVisible', false);
export const EditorsVisibleContext = new RawContextKey<boolean>('editorIsOpen', false);
I
isidor 已提交
106
export const InZenModeContext = new RawContextKey<boolean>('inZenMode', false);
J
Johannes Rieken 已提交
107
export const NoEditorsVisibleContext: ContextKeyExpr = EditorsVisibleContext.toNegated();
A
Alex Dima 已提交
108

E
Erich Gamma 已提交
109 110
interface WorkbenchParams {
	options: IOptions;
111
	configuration: IWindowConfiguration;
112
	serviceCollection: ServiceCollection;
E
Erich Gamma 已提交
113 114
}

I
isidor 已提交
115 116 117
interface IZenModeSettings {
	fullScreen: boolean;
	hideTabs: boolean;
118
	hideActivityBar: boolean;
I
isidor 已提交
119
	hideStatusBar: boolean;
I
isidor 已提交
120
	restore: boolean;
I
isidor 已提交
121 122
}

123 124 125 126 127
export interface IWorkbenchStartedInfo {
	customKeybindingsCount: number;
	restoreViewletDuration: number;
	restoreEditorsDuration: number;
	pinnedViewlets: string[];
128 129
	restoredViewlet: string;
	restoredEditors: string[];
130 131
}

E
Erich Gamma 已提交
132 133
export interface IWorkbenchCallbacks {
	onServicesCreated?: () => void;
134
	onWorkbenchStarted?: (info: IWorkbenchStartedInfo) => void;
E
Erich Gamma 已提交
135 136
}

137 138
const Identifiers = {
	WORKBENCH_CONTAINER: 'workbench.main.container',
B
Benjamin Pasero 已提交
139
	TITLEBAR_PART: 'workbench.parts.titlebar',
140 141 142 143 144 145 146
	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 已提交
147
/**
B
Benjamin Pasero 已提交
148
 * The workbench creates and lays out all parts that make up the workbench.
E
Erich Gamma 已提交
149 150 151 152
 */
export class Workbench implements IPartService {

	private static sidebarHiddenSettingKey = 'workbench.sidebar.hidden';
153
	private static sidebarRestoreSettingKey = 'workbench.sidebar.restore';
I
isidor 已提交
154
	private static panelHiddenSettingKey = 'workbench.panel.hidden';
I
isidor 已提交
155
	private static zenModeActiveSettingKey = 'workbench.zenmode.active';
E
Erich Gamma 已提交
156

157
	private static sidebarPositionConfigurationKey = 'workbench.sideBar.location';
158
	private static statusbarVisibleConfigurationKey = 'workbench.statusBar.visible';
S
Sanders Lauture 已提交
159
	private static activityBarVisibleConfigurationKey = 'workbench.activityBar.visible';
160

161 162
	private static closeWhenEmptyConfigurationKey = 'window.closeWhenEmpty';

163 164
	private static fontAliasingConfigurationKey = 'workbench.fontAliasing';

165 166
	private _onTitleBarVisibilityChange: Emitter<void>;

167
	public _serviceBrand: any;
E
Erich Gamma 已提交
168

B
Benjamin Pasero 已提交
169
	private parent: HTMLElement;
E
Erich Gamma 已提交
170 171 172 173 174 175 176
	private container: HTMLElement;
	private workbenchParams: WorkbenchParams;
	private workbenchContainer: Builder;
	private workbench: Builder;
	private workbenchStarted: boolean;
	private workbenchCreated: boolean;
	private workbenchShutdown: boolean;
177
	private editorService: WorkbenchEditorService;
P
Pine Wu 已提交
178
	private viewletService: IViewletService;
179
	private contextKeyService: IContextKeyService;
180
	private keybindingService: IKeybindingService;
181
	private backupFileService: IBackupFileService;
182
	private configurationEditingService: IConfigurationEditingService;
B
Benjamin Pasero 已提交
183
	private titlebarPart: TitlebarPart;
E
Erich Gamma 已提交
184 185
	private activitybarPart: ActivitybarPart;
	private sidebarPart: SidebarPart;
I
isidor 已提交
186
	private panelPart: PanelPart;
E
Erich Gamma 已提交
187 188 189 190 191 192 193 194 195 196
	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;
197
	private statusBarHidden: boolean;
S
Sanders Lauture 已提交
198
	private activityBarHidden: boolean;
E
Erich Gamma 已提交
199
	private sideBarPosition: Position;
I
isidor 已提交
200
	private panelHidden: boolean;
E
Erich Gamma 已提交
201
	private editorBackgroundDelayer: Delayer<void>;
202
	private closeEmptyWindowScheduler: RunOnceScheduler;
A
Alex Dima 已提交
203 204
	private messagesVisibleContext: IContextKey<boolean>;
	private editorsVisibleContext: IContextKey<boolean>;
I
isidor 已提交
205
	private inZenMode: IContextKey<boolean>;
206
	private hasFilesToCreateOpenOrDiff: boolean;
207
	private fontAliasing: string;
I
isidor 已提交
208
	private zenMode: {
I
isidor 已提交
209 210
		active: boolean;
		transitionedToFullScreen: boolean;
211 212
		wasSideBarVisible: boolean;
		wasPanelVisible: boolean;
I
isidor 已提交
213
	};
E
Erich Gamma 已提交
214

215
	constructor(
B
Benjamin Pasero 已提交
216
		parent: HTMLElement,
217
		container: HTMLElement,
218
		configuration: IWindowConfiguration,
219 220
		options: IOptions,
		serviceCollection: ServiceCollection,
221
		@IInstantiationService private instantiationService: IInstantiationService,
222
		@IWorkspaceContextService private contextService: IWorkspaceContextService,
223 224 225
		@IStorageService private storageService: IStorageService,
		@ILifecycleService private lifecycleService: ILifecycleService,
		@IMessageService private messageService: IMessageService,
226
		@IConfigurationService private configurationService: WorkspaceService,
227
		@ITelemetryService private telemetryService: ITelemetryService,
I
isidor 已提交
228 229
		@IEnvironmentService private environmentService: IEnvironmentService,
		@IWindowService private windowService: IWindowService
230
	) {
B
Benjamin Pasero 已提交
231
		this.parent = parent;
232
		this.container = container;
E
Erich Gamma 已提交
233 234

		this.workbenchParams = {
235
			options,
236
			configuration,
237
			serviceCollection
E
Erich Gamma 已提交
238 239
		};

240 241 242
		this.hasFilesToCreateOpenOrDiff =
			(options.filesToCreate && options.filesToCreate.length > 0) ||
			(options.filesToOpen && options.filesToOpen.length > 0) ||
243
			(options.filesToDiff && options.filesToDiff.length > 0);
244

E
Erich Gamma 已提交
245 246
		this.toDispose = [];
		this.toShutdown = [];
247

E
Erich Gamma 已提交
248
		this.editorBackgroundDelayer = new Delayer<void>(50);
249
		this.closeEmptyWindowScheduler = new RunOnceScheduler(() => this.onAllEditorsClosed(), 50);
E
Erich Gamma 已提交
250

251 252
		this._onTitleBarVisibilityChange = new Emitter<void>();

253
		this.creationPromise = new TPromise<boolean>(c => {
E
Erich Gamma 已提交
254 255 256 257
			this.creationPromiseComplete = c;
		});
	}

258 259 260 261
	public get onTitleBarVisibilityChange(): Event<void> {
		return this._onTitleBarVisibilityChange.event;
	}

262 263 264 265 266 267
	public get onEditorLayout(): Event<void> {
		return chain(this.editorPart.onLayout)
			.map(() => void 0)
			.event;
	}

E
Erich Gamma 已提交
268 269 270 271 272 273 274 275 276 277 278 279 280 281 282
	/**
	 * 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();

283 284 285
			// Install some global actions
			this.createGlobalActions();

E
Erich Gamma 已提交
286 287 288 289 290 291
			// Services
			this.initServices();
			if (this.callbacks && this.callbacks.onServicesCreated) {
				this.callbacks.onServicesCreated();
			}

292
			// Contexts
293 294
			this.messagesVisibleContext = MessagesVisibleContext.bindTo(this.contextKeyService);
			this.editorsVisibleContext = EditorsVisibleContext.bindTo(this.contextKeyService);
I
isidor 已提交
295
			this.inZenMode = InZenModeContext.bindTo(this.contextKeyService);
296

E
Erich Gamma 已提交
297 298 299 300 301 302 303 304 305 306 307 308
			// Register Listeners
			this.registerListeners();

			// Settings
			this.initSettings();

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

			// Workbench Layout
			this.createWorkbenchLayout();

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

P
Pine Wu 已提交
312
			// Restore last opened viewlet
313
			let viewletRestoreStopWatch: StopWatch;
314
			let viewletIdToRestore: string;
315
			if (!this.sideBarHidden) {
316

317
				if (this.shouldRestoreLastOpenedViewlet()) {
318
					viewletIdToRestore = this.storageService.get(SidebarPart.activeViewletSettingsKey, StorageScope.WORKSPACE);
B
polish  
Benjamin Pasero 已提交
319 320 321
				}

				if (!viewletIdToRestore) {
322
					viewletIdToRestore = this.viewletService.getDefaultViewletId();
P
Pine Wu 已提交
323
				}
324

325
				viewletRestoreStopWatch = StopWatch.create();
326 327
				const viewletTimer = startTimer('restore:viewlet');
				compositeAndEditorPromises.push(viewletTimer.while(this.viewletService.openViewlet(viewletIdToRestore)).then(() => {
328 329
					viewletRestoreStopWatch.stop();
				}));
E
Erich Gamma 已提交
330 331
			}

B
Benjamin Pasero 已提交
332
			// Load Panel
333
			const panelRegistry = Registry.as<PanelRegistry>(PanelExtensions.Panels);
334 335
			const panelId = this.storageService.get(PanelPart.activePanelSettingsKey, StorageScope.WORKSPACE, panelRegistry.getDefaultPanelId());
			if (!this.panelHidden && !!panelId) {
I
isidor 已提交
336
				compositeAndEditorPromises.push(this.panelPart.openPanel(panelId, false));
337 338
			}

B
Benjamin Pasero 已提交
339
			// Load Editors
340
			const editorRestoreStopWatch = StopWatch.create();
341
			const restoredEditors: string[] = [];
342 343
			const editorsTimer = startTimer('restore:editors');
			compositeAndEditorPromises.push(editorsTimer.while(this.resolveEditorsToOpen().then(inputs => {
344
				let editorOpenPromise: TPromise<IEditor[]>;
345 346
				if (inputs.length) {
					editorOpenPromise = this.editorService.openEditors(inputs.map(input => { return { input, position: EditorPosition.ONE }; }));
B
Benjamin Pasero 已提交
347
				} else {
B
Benjamin Pasero 已提交
348
					editorOpenPromise = this.editorPart.restoreEditors();
349
				}
350

351
				return editorOpenPromise.then(editors => {
B
Benjamin Pasero 已提交
352
					this.handleEditorBackground(); // make sure we show the proper background in the editor area
353
					editorRestoreStopWatch.stop();
B
Benjamin Pasero 已提交
354

355
					for (const editor of editors) {
B
Benjamin Pasero 已提交
356 357 358 359 360 361
						if (editor) {
							if (editor.input) {
								restoredEditors.push(editor.input.getName());
							} else {
								restoredEditors.push(`other:${editor.getId()}`);
							}
362 363
						}
					}
E
Erich Gamma 已提交
364
				});
365
			})));
E
Erich Gamma 已提交
366

367
			if (this.storageService.getBoolean(Workbench.zenModeActiveSettingKey, StorageScope.WORKSPACE, false)) {
I
isidor 已提交
368 369 370
				this.toggleZenMode(true);
			}

E
Erich Gamma 已提交
371
			// Flag workbench as created once done
372
			const workbenchDone = (error?: Error) => {
E
Erich Gamma 已提交
373 374 375
				this.workbenchCreated = true;
				this.creationPromiseComplete(true);

B
Benjamin Pasero 已提交
376
				if (this.callbacks && this.callbacks.onWorkbenchStarted) {
377 378
					this.callbacks.onWorkbenchStarted({
						customKeybindingsCount: this.keybindingService.customKeybindingsCount(),
379 380
						restoreViewletDuration: viewletRestoreStopWatch ? Math.round(viewletRestoreStopWatch.elapsed()) : 0,
						restoreEditorsDuration: Math.round(editorRestoreStopWatch.elapsed()),
B
Benjamin Pasero 已提交
381
						pinnedViewlets: this.activitybarPart.getPinned(),
382 383
						restoredViewlet: viewletIdToRestore,
						restoredEditors
384
					});
B
Benjamin Pasero 已提交
385
				}
386 387 388 389 390 391

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

B
polish  
Benjamin Pasero 已提交
392
			// Join viewlet, panel and editor promises
393
			TPromise.join(compositeAndEditorPromises).then(() => workbenchDone(), error => workbenchDone(error));
E
Erich Gamma 已提交
394 395 396
		} catch (error) {

			// Print out error
397
			console.error(toErrorMessage(error, true));
E
Erich Gamma 已提交
398 399 400 401 402 403

			// Rethrow
			throw error;
		}
	}

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

B
Benjamin Pasero 已提交
407
		// Actions registered here to adjust for developing vs built workbench
408 409
		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 已提交
410
		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 已提交
411
		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"));
412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433

		const recentFilesPickerContext = ContextKeyExpr.and(inQuickOpenContext, ContextKeyExpr.has(inRecentFilesPickerContextKey));

		const quickOpenNavigateNextInRecentFilesPickerId = 'workbench.action.quickOpenNavigateNextInRecentFilesPicker';
		KeybindingsRegistry.registerCommandAndKeybindingRule({
			id: quickOpenNavigateNextInRecentFilesPickerId,
			weight: KeybindingsRegistry.WEIGHT.workbenchContrib(50),
			handler: getQuickNavigateHandler(quickOpenNavigateNextInRecentFilesPickerId, true),
			when: recentFilesPickerContext,
			primary: KeyMod.CtrlCmd | KeyCode.KEY_R,
			mac: { primary: KeyMod.WinCtrl | KeyCode.KEY_R }
		});

		const quickOpenNavigatePreviousInRecentFilesPicker = 'workbench.action.quickOpenNavigatePreviousInRecentFilesPicker';
		KeybindingsRegistry.registerCommandAndKeybindingRule({
			id: quickOpenNavigatePreviousInRecentFilesPicker,
			weight: KeybindingsRegistry.WEIGHT.workbenchContrib(50),
			handler: getQuickNavigateHandler(quickOpenNavigatePreviousInRecentFilesPicker, false),
			when: recentFilesPickerContext,
			primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_R,
			mac: { primary: KeyMod.WinCtrl | KeyMod.Shift | KeyCode.KEY_R }
		});
434 435
	}

436
	private resolveEditorsToOpen(): TPromise<IResourceInputType[]> {
B
Benjamin Pasero 已提交
437 438

		// Files to open, diff or create
439 440
		if (this.hasFilesToCreateOpenOrDiff) {
			const wbopt = this.workbenchParams.options;
B
Benjamin Pasero 已提交
441 442 443
			const filesToCreate = wbopt.filesToCreate || [];
			const filesToOpen = wbopt.filesToOpen || [];
			const filesToDiff = wbopt.filesToDiff;
B
Benjamin Pasero 已提交
444 445

			// Files to diff is exclusive
446
			if (filesToDiff && filesToDiff.length === 2) {
447 448 449 450 451
				return TPromise.as([<IResourceDiffInput>{
					leftResource: filesToDiff[0].resource,
					rightResource: filesToDiff[1].resource,
					options: { pinned: true }
				}]);
B
Benjamin Pasero 已提交
452 453 454 455
			}

			// Otherwise: Open/Create files
			else {
456 457 458
				const filesToCreateInputs: IUntitledResourceInput[] = filesToCreate.map(resourceInput => {
					return <IUntitledResourceInput>{
						filePath: resourceInput.resource.fsPath,
459 460
						options: { pinned: true }
					};
B
Benjamin Pasero 已提交
461
				});
462

463
				return TPromise.as([].concat(filesToOpen).concat(filesToCreateInputs));
B
Benjamin Pasero 已提交
464 465 466
			}
		}

467 468
		// Empty workbench
		else if (!this.contextService.hasWorkspace() && this.openUntitledFile()) {
469 470 471 472
			if (this.editorPart.hasEditorsToRestore()) {
				return TPromise.as([]); // do not open any empty untitled file if we have editors to restore
			}

473 474 475 476 477
			return this.backupFileService.hasBackups().then(hasBackups => {
				if (hasBackups) {
					return TPromise.as([]); // do not open any empty untitled file if we have backups to restore
				}

478
				return TPromise.as([<IUntitledResourceInput>{}]);
479
			});
B
Benjamin Pasero 已提交
480 481 482 483 484
		}

		return TPromise.as([]);
	}

485
	private openUntitledFile() {
486
		const startupEditor = this.configurationService.lookup('workbench.startupEditor');
B
Benjamin Pasero 已提交
487 488

		// Fallback to previous workbench.welcome.enabled setting in case startupEditor is not defined
489 490
		if (!startupEditor.user && !startupEditor.workspace) {
			const welcomeEnabled = this.configurationService.lookup('workbench.welcome.enabled');
B
Benjamin Pasero 已提交
491
			if (typeof welcomeEnabled.value === 'boolean') {
492 493 494
				return !welcomeEnabled.value;
			}
		}
B
Benjamin Pasero 已提交
495

496
		return startupEditor.value === 'newUntitledFile';
497 498
	}

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

502
		this.toDispose.push(this.lifecycleService.onShutdown(this.shutdownComponents, this));
E
Erich Gamma 已提交
503 504

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

507 508 509
		// Clipboard
		serviceCollection.set(IClipboardService, new ClipboardService());

510 511 512 513 514 515
		// 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);

516 517 518
		// Progress 2
		serviceCollection.set(IProgressService2, new SyncDescriptor(ProgressService2));

519
		// Keybindings
A
Alex Dima 已提交
520
		this.contextKeyService = this.instantiationService.createInstance(ContextKeyService);
521
		serviceCollection.set(IContextKeyService, this.contextKeyService);
522

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

526 527 528
		// List
		serviceCollection.set(IListService, this.instantiationService.createInstance(ListService));

529
		// Context Menu
530
		serviceCollection.set(IContextMenuService, new SyncDescriptor(ContextMenuService));
531

532 533
		// Menus/Actions
		serviceCollection.set(IMenuService, new SyncDescriptor(MenuService));
534

P
Pine Wu 已提交
535
		// Sidebar part
536
		this.sidebarPart = this.instantiationService.createInstance(SidebarPart, Identifiers.SIDEBAR_PART);
E
Erich Gamma 已提交
537 538
		this.toDispose.push(this.sidebarPart);
		this.toShutdown.push(this.sidebarPart);
P
Pine Wu 已提交
539 540 541 542

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

I
isidor 已提交
544
		// Panel service (panel part)
545
		this.panelPart = this.instantiationService.createInstance(PanelPart, Identifiers.PANEL_PART);
I
isidor 已提交
546 547
		this.toDispose.push(this.panelPart);
		this.toShutdown.push(this.panelPart);
548
		serviceCollection.set(IPanelService, this.panelPart);
I
isidor 已提交
549

E
Erich Gamma 已提交
550
		// Activity service (activitybar part)
551
		this.activitybarPart = this.instantiationService.createInstance(ActivitybarPart, Identifiers.ACTIVITYBAR_PART);
E
Erich Gamma 已提交
552 553
		this.toDispose.push(this.activitybarPart);
		this.toShutdown.push(this.activitybarPart);
554
		serviceCollection.set(IActivityBarService, this.activitybarPart);
E
Erich Gamma 已提交
555 556

		// Editor service (editor part)
557
		this.editorPart = this.instantiationService.createInstance(EditorPart, Identifiers.EDITOR_PART, !this.hasFilesToCreateOpenOrDiff);
E
Erich Gamma 已提交
558 559
		this.toDispose.push(this.editorPart);
		this.toShutdown.push(this.editorPart);
560
		this.editorService = this.instantiationService.createInstance(WorkbenchEditorService, this.editorPart);
561
		serviceCollection.set(IWorkbenchEditorService, this.editorService);
562
		serviceCollection.set(IEditorGroupService, this.editorPart);
E
Erich Gamma 已提交
563

564 565 566 567 568 569
		// 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);

570
		// File Service
571 572 573
		const fileService = this.instantiationService.createInstance(FileService);
		serviceCollection.set(IFileService, fileService);
		this.toDispose.push(fileService.onFileChanges(e => this.configurationService.handleWorkspaceFileEvents(e)));
574

575
		// History
576
		serviceCollection.set(IHistoryService, new SyncDescriptor(HistoryService));
577

578
		// Backup File Service
579
		this.backupFileService = this.instantiationService.createInstance(BackupFileService, this.workbenchParams.configuration.backupPath);
580
		serviceCollection.set(IBackupFileService, this.backupFileService);
581

582
		// Text File Service
583
		serviceCollection.set(ITextFileService, new SyncDescriptor(TextFileService));
584

J
Joao Moreno 已提交
585
		// SCM Service
586
		serviceCollection.set(ISCMService, new SyncDescriptor(SCMService));
587

B
Benjamin Pasero 已提交
588
		// Text Model Resolver Service
589
		serviceCollection.set(ITextModelService, new SyncDescriptor(TextModelResolverService));
B
Benjamin Pasero 已提交
590

591 592 593 594
		// JSON Editing
		const jsonEditingService = this.instantiationService.createInstance(JSONEditingService);
		serviceCollection.set(IJSONEditingService, jsonEditingService);

595
		// Configuration Editing
596 597
		this.configurationEditingService = this.instantiationService.createInstance(ConfigurationEditingService);
		serviceCollection.set(IConfigurationEditingService, this.configurationEditingService);
598

599 600 601
		// Workspace Editing
		serviceCollection.set(IWorkspaceEditingService, new SyncDescriptor(WorkspaceEditingService));

602 603 604
		// Keybinding Editing
		serviceCollection.set(IKeybindingEditingService, this.instantiationService.createInstance(KeybindingsEditingService));

605
		// Configuration Resolver
B
Benjamin Pasero 已提交
606
		serviceCollection.set(IConfigurationResolverService, new SyncDescriptor(ConfigurationResolverService, process.env));
607

E
Erich Gamma 已提交
608
		// Quick open service (quick open controller)
609
		this.quickOpen = this.instantiationService.createInstance(QuickOpenController);
E
Erich Gamma 已提交
610 611
		this.toDispose.push(this.quickOpen);
		this.toShutdown.push(this.quickOpen);
612
		serviceCollection.set(IQuickOpenService, this.quickOpen);
E
Erich Gamma 已提交
613

B
polish  
Benjamin Pasero 已提交
614
		// Contributed services
B
Benjamin Pasero 已提交
615
		const contributedServices = getServices();
E
Erich Gamma 已提交
616
		for (let contributedService of contributedServices) {
617
			serviceCollection.set(contributedService.id, contributedService.descriptor);
E
Erich Gamma 已提交
618 619 620
		}

		// Set the some services to registries that have been created eagerly
621 622 623
		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 已提交
624 625 626 627 628
	}

	private initSettings(): void {

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

I
isidor 已提交
631
		// Panel part visibility
632
		const panelRegistry = Registry.as<PanelRegistry>(PanelExtensions.Panels);
B
Benjamin Pasero 已提交
633
		this.panelHidden = this.storageService.getBoolean(Workbench.panelHiddenSettingKey, StorageScope.WORKSPACE, true);
634 635
		if (!panelRegistry.getDefaultPanelId()) {
			this.panelHidden = true; // we hide panel part if there is no default panel
I
isidor 已提交
636
		}
I
isidor 已提交
637

E
Erich Gamma 已提交
638
		// Sidebar position
639 640
		const sideBarPosition = this.configurationService.lookup<string>(Workbench.sidebarPositionConfigurationKey).value;
		this.sideBarPosition = (sideBarPosition === 'right') ? Position.RIGHT : Position.LEFT;
B
Benjamin Pasero 已提交
641 642

		// Statusbar visibility
643 644
		const statusBarVisible = this.configurationService.lookup<string>(Workbench.statusbarVisibleConfigurationKey).value;
		this.statusBarHidden = !statusBarVisible;
S
Sanders Lauture 已提交
645 646 647 648

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

650 651 652
		// Font aliasing
		this.fontAliasing = this.configurationService.lookup<string>(Workbench.fontAliasingConfigurationKey).value;

I
isidor 已提交
653 654
		// Zen mode
		this.zenMode = {
I
isidor 已提交
655
			active: false,
656 657 658
			transitionedToFullScreen: false,
			wasSideBarVisible: false,
			wasPanelVisible: false
I
isidor 已提交
659
		};
E
Erich Gamma 已提交
660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680
	}

	/**
	 * 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 已提交
681
		const activeElement = document.activeElement;
E
Erich Gamma 已提交
682 683 684 685
		if (!activeElement) {
			return false;
		}

686 687 688 689 690
		const container = this.getContainer(part);
		return DOM.isAncestor(activeElement, container);
	}

	public getContainer(part: Parts): HTMLElement {
E
Erich Gamma 已提交
691 692
		let container: Builder = null;
		switch (part) {
B
Benjamin Pasero 已提交
693 694 695
			case Parts.TITLEBAR_PART:
				container = this.titlebarPart.getContainer();
				break;
E
Erich Gamma 已提交
696 697 698 699 700 701
			case Parts.ACTIVITYBAR_PART:
				container = this.activitybarPart.getContainer();
				break;
			case Parts.SIDEBAR_PART:
				container = this.sidebarPart.getContainer();
				break;
I
isidor 已提交
702 703 704
			case Parts.PANEL_PART:
				container = this.panelPart.getContainer();
				break;
E
Erich Gamma 已提交
705 706 707 708 709 710 711
			case Parts.EDITOR_PART:
				container = this.editorPart.getContainer();
				break;
			case Parts.STATUSBAR_PART:
				container = this.statusbarPart.getContainer();
				break;
		}
712
		return container && container.getHTMLElement();
E
Erich Gamma 已提交
713 714 715
	}

	public isVisible(part: Parts): boolean {
B
Benjamin Pasero 已提交
716
		switch (part) {
B
Benjamin Pasero 已提交
717
			case Parts.TITLEBAR_PART:
718
				return this.getCustomTitleBarStyle() && !browser.isFullscreen();
B
Benjamin Pasero 已提交
719
			case Parts.SIDEBAR_PART:
720
				return !this.sideBarHidden;
B
Benjamin Pasero 已提交
721
			case Parts.PANEL_PART:
722
				return !this.panelHidden;
B
Benjamin Pasero 已提交
723
			case Parts.STATUSBAR_PART:
724
				return !this.statusBarHidden;
S
Sanders Lauture 已提交
725
			case Parts.ACTIVITYBAR_PART:
726
				return !this.activityBarHidden;
727
		}
E
Erich Gamma 已提交
728 729 730 731

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

732 733
	public getTitleBarOffset(): number {
		let offset = 0;
734
		if (this.isVisible(Parts.TITLEBAR_PART)) {
735 736 737 738 739 740
			offset = 22 / browser.getZoomFactor(); // adjust the position based on title bar size and zoom factor
		}

		return offset;
	}

741
	private getCustomTitleBarStyle(): 'custom' {
B
Benjamin Pasero 已提交
742
		if (!isMacintosh) {
743
			return null; // custom title bar is only supported on Mac currently
B
Benjamin Pasero 已提交
744 745
		}

746
		const isDev = !this.environmentService.isBuilt || this.environmentService.isExtensionDevelopment;
B
Benjamin Pasero 已提交
747
		if (isDev) {
748
			return null; // not enabled when developing due to https://github.com/electron/electron/issues/3647
B
Benjamin Pasero 已提交
749 750
		}

751
		const windowConfig = this.configurationService.getConfiguration<IWindowSettings>();
752 753 754 755 756
		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 已提交
757

758 759 760 761
			const style = windowConfig.window.titleBarStyle;
			if (style === 'custom') {
				return style;
			}
762 763 764
		}

		return null;
B
Benjamin Pasero 已提交
765 766
	}

767
	private setStatusBarHidden(hidden: boolean, skipLayout?: boolean): void {
768 769
		this.statusBarHidden = hidden;

I
isidor 已提交
770

771 772
		// Layout
		if (!skipLayout) {
773
			this.workbenchLayout.layout();
774 775 776
		}
	}

S
Sanders Lauture 已提交
777 778 779
	public setActivityBarHidden(hidden: boolean, skipLayout?: boolean): void {
		this.activityBarHidden = hidden;

I
isidor 已提交
780

S
Sanders Lauture 已提交
781 782
		// Layout
		if (!skipLayout) {
783
			this.workbenchLayout.layout();
S
Sanders Lauture 已提交
784 785 786
		}
	}

787
	public setSideBarHidden(hidden: boolean, skipLayout?: boolean): TPromise<void> {
E
Erich Gamma 已提交
788 789 790 791 792 793 794 795 796
		this.sideBarHidden = hidden;

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

B
Benjamin Pasero 已提交
797
		// If sidebar becomes hidden, also hide the current active Viewlet if any
B
Benjamin Pasero 已提交
798
		let promise = TPromise.as<any>(null);
E
Erich Gamma 已提交
799
		if (hidden && this.sidebarPart.getActiveViewlet()) {
800 801 802
			promise = this.sidebarPart.hideActiveViewlet().then(() => {
				const activeEditor = this.editorPart.getActiveEditor();
				const activePanel = this.panelPart.getActivePanel();
B
Benjamin Pasero 已提交
803

804 805 806 807 808 809 810
				// 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 已提交
811 812
		}

B
Benjamin Pasero 已提交
813
		// If sidebar becomes visible, show last active Viewlet or default viewlet
E
Erich Gamma 已提交
814
		else if (!hidden && !this.sidebarPart.getActiveViewlet()) {
815
			const viewletToOpen = this.sidebarPart.getLastActiveViewletId();
E
Erich Gamma 已提交
816
			if (viewletToOpen) {
817
				promise = this.sidebarPart.openViewlet(viewletToOpen, true);
E
Erich Gamma 已提交
818 819 820
			}
		}

821
		return promise.then(() => {
822

823
			// Remember in settings
824 825 826 827 828 829
			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);
			}
830 831 832

			// Layout
			if (!skipLayout) {
833
				this.workbenchLayout.layout();
834 835
			}
		});
E
Erich Gamma 已提交
836 837
	}

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

841 842 843 844 845 846 847
		// Adjust CSS
		if (hidden) {
			this.workbench.addClass('nopanel');
		} else {
			this.workbench.removeClass('nopanel');
		}

I
isidor 已提交
848
		// If panel part becomes hidden, also hide the current active panel if any
849
		let promise = TPromise.as<any>(null);
I
isidor 已提交
850
		if (hidden && this.panelPart.getActivePanel()) {
851 852 853 854 855 856 857
			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 已提交
858 859 860 861
		}

		// If panel part becomes visible, show last active panel or default panel
		else if (!hidden && !this.panelPart.getActivePanel()) {
862
			const panelToOpen = this.panelPart.getLastActivePanelId();
I
isidor 已提交
863
			if (panelToOpen) {
864
				promise = this.panelPart.openPanel(panelToOpen, true);
I
isidor 已提交
865 866 867
			}
		}

868
		return promise.then(() => {
869

870
			// Remember in settings
871 872 873 874 875
			if (!hidden) {
				this.storageService.store(Workbench.panelHiddenSettingKey, 'false', StorageScope.WORKSPACE);
			} else {
				this.storageService.remove(Workbench.panelHiddenSettingKey, StorageScope.WORKSPACE);
			}
876 877 878

			// Layout
			if (!skipLayout) {
879
				this.workbenchLayout.layout();
880 881
			}
		});
I
isidor 已提交
882 883
	}

I
isidor 已提交
884
	public toggleMaximizedPanel(): void {
885
		this.workbenchLayout.layout({ toggleMaximizedPanel: true });
I
isidor 已提交
886 887
	}

I
isidor 已提交
888 889 890 891
	public isPanelMaximized(): boolean {
		return this.workbenchLayout.isPanelMaximized();
	}

E
Erich Gamma 已提交
892 893 894 895
	public getSideBarPosition(): Position {
		return this.sideBarPosition;
	}

896
	private setSideBarPosition(position: Position): void {
E
Erich Gamma 已提交
897
		if (this.sideBarHidden) {
898
			this.setSideBarHidden(false, true /* Skip Layout */).done(undefined, errors.onUnexpectedError);
E
Erich Gamma 已提交
899 900
		}

B
Benjamin Pasero 已提交
901 902
		const newPositionValue = (position === Position.LEFT) ? 'left' : 'right';
		const oldPositionValue = (this.sideBarPosition === Position.LEFT) ? 'left' : 'right';
E
Erich Gamma 已提交
903 904 905 906 907 908 909 910
		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);

911 912 913 914
		// Update Styles
		this.activitybarPart.updateStyles();
		this.sidebarPart.updateStyles();

E
Erich Gamma 已提交
915
		// Layout
916
		this.workbenchLayout.layout();
E
Erich Gamma 已提交
917 918
	}

919 920 921 922 923
	private setFontAliasing(aliasing: string) {
		this.fontAliasing = aliasing;
		document.body.style['-webkit-font-smoothing'] = (aliasing === 'default' ? '' : aliasing);
	}

B
Benjamin Pasero 已提交
924
	public dispose(): void {
E
Erich Gamma 已提交
925
		if (this.isStarted()) {
B
Benjamin Pasero 已提交
926
			this.shutdownComponents();
E
Erich Gamma 已提交
927 928 929
			this.workbenchShutdown = true;
		}

J
Joao Moreno 已提交
930
		this.toDispose = dispose(this.toDispose);
E
Erich Gamma 已提交
931 932 933 934 935 936
	}

	/**
	 * 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 已提交
937
	public layout(options?: ILayoutOptions): void {
E
Erich Gamma 已提交
938
		if (this.isStarted()) {
B
Benjamin Pasero 已提交
939
			this.workbenchLayout.layout(options);
E
Erich Gamma 已提交
940 941 942
		}
	}

943 944 945 946 947 948
	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 已提交
949

I
isidor 已提交
950
		// Preserve zen mode only on reload. Real quit gets out of zen mode so novice users do not get stuck in zen mode.
951 952 953 954 955 956 957
		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 已提交
958 959 960 961 962 963 964 965

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

	private registerListeners(): void {

		// Listen to editor changes
966
		this.toDispose.push(this.editorPart.onEditorsChanged(() => this.onEditorsChanged()));
967 968

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

972 973 974 975 976
		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()));
977 978 979 980 981 982 983 984 985 986

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

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

987
		// Apply as CSS class
988 989 990 991 992
		const isFullscreen = browser.isFullscreen();
		if (isFullscreen) {
			this.addClass('fullscreen');
		} else {
			this.removeClass('fullscreen');
I
isidor 已提交
993 994
			if (this.zenMode.transitionedToFullScreen && this.zenMode.active) {
				this.toggleZenMode();
I
isidor 已提交
995
			}
996
		}
997

998 999 1000 1001 1002
		// 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
1003
		}
E
Erich Gamma 已提交
1004 1005
	}

1006
	private onEditorsChanged(): void {
B
Benjamin Pasero 已提交
1007
		const visibleEditors = this.editorService.getVisibleEditors().length;
E
Erich Gamma 已提交
1008

1009 1010
		// Close when empty: check if we should close the window based on the setting
		// Overruled by: window has a workspace opened or this window is for extension development
1011
		// or setting is disabled. Also enabled when running with --wait from the command line.
1012 1013
		if (visibleEditors === 0 && !this.contextService.hasWorkspace() && !this.environmentService.isExtensionDevelopment) {
			const closeWhenEmpty = this.configurationService.lookup<boolean>(Workbench.closeWhenEmptyConfigurationKey).value;
1014
			if (closeWhenEmpty || this.environmentService.args.wait) {
1015 1016 1017 1018
				this.closeEmptyWindowScheduler.schedule();
			}
		}

E
Erich Gamma 已提交
1019 1020
		// We update the editorpart class to indicate if an editor is opened or not
		// through a delay to accomodate for fast editor switching
B
Benjamin Pasero 已提交
1021 1022 1023 1024 1025 1026
		this.handleEditorBackground();
	}

	private handleEditorBackground(): void {
		const visibleEditors = this.editorService.getVisibleEditors().length;

1027
		const editorContainer = this.editorPart.getContainer();
E
Erich Gamma 已提交
1028
		if (visibleEditors === 0) {
1029
			this.editorsVisibleContext.reset();
1030
			this.editorBackgroundDelayer.trigger(() => editorContainer.addClass('empty'));
E
Erich Gamma 已提交
1031
		} else {
1032
			this.editorsVisibleContext.set(true);
1033
			this.editorBackgroundDelayer.trigger(() => editorContainer.removeClass('empty'));
E
Erich Gamma 已提交
1034 1035 1036
		}
	}

1037 1038 1039 1040 1041 1042 1043
	private onAllEditorsClosed(): void {
		const visibleEditors = this.editorService.getVisibleEditors().length;
		if (visibleEditors === 0) {
			this.windowService.closeWindow();
		}
	}

1044
	private onDidUpdateConfiguration(skipLayout?: boolean): void {
1045
		const newSidebarPositionValue = this.configurationService.lookup<string>(Workbench.sidebarPositionConfigurationKey).value;
1046
		const newSidebarPosition = (newSidebarPositionValue === 'right') ? Position.RIGHT : Position.LEFT;
1047 1048 1049
		if (newSidebarPosition !== this.getSideBarPosition()) {
			this.setSideBarPosition(newSidebarPosition);
		}
1050

1051 1052 1053 1054 1055
		const fontAliasing = this.configurationService.lookup<string>(Workbench.fontAliasingConfigurationKey).value;
		if (fontAliasing !== this.fontAliasing) {
			this.setFontAliasing(fontAliasing);
		}

1056 1057 1058 1059 1060
		if (!this.zenMode.active) {
			const newStatusbarHiddenValue = !this.configurationService.lookup<boolean>(Workbench.statusbarVisibleConfigurationKey).value;
			if (newStatusbarHiddenValue !== this.statusBarHidden) {
				this.setStatusBarHidden(newStatusbarHiddenValue, skipLayout);
			}
S
Sanders Lauture 已提交
1061

1062 1063 1064 1065
			const newActivityBarHiddenValue = !this.configurationService.lookup<boolean>(Workbench.activityBarVisibleConfigurationKey).value;
			if (newActivityBarHiddenValue !== this.activityBarHidden) {
				this.setActivityBarHidden(newActivityBarHiddenValue, skipLayout);
			}
S
Sanders Lauture 已提交
1066
		}
1067 1068
	}

E
Erich Gamma 已提交
1069 1070 1071 1072
	private createWorkbenchLayout(): void {
		this.workbenchLayout = this.instantiationService.createInstance(WorkbenchLayout,
			$(this.container),							// Parent
			this.workbench,								// Workbench Container
I
isidor 已提交
1073
			{
B
Benjamin Pasero 已提交
1074
				titlebar: this.titlebarPart,			// Title Bar
I
isidor 已提交
1075 1076 1077 1078 1079 1080
				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 已提交
1081
			this.quickOpen								// Quickopen
E
Erich Gamma 已提交
1082 1083 1084 1085 1086 1087 1088 1089 1090
		);

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

	private createWorkbench(): void {

		// Create Workbench DIV Off-DOM
		this.workbenchContainer = $('.monaco-workbench-container');
1091
		this.workbench = $().div({ 'class': 'monaco-workbench ' + (isWindows ? 'windows' : isLinux ? 'linux' : 'mac'), id: Identifiers.WORKBENCH_CONTAINER }).appendTo(this.workbenchContainer);
E
Erich Gamma 已提交
1092 1093 1094 1095 1096 1097 1098 1099
	}

	private renderWorkbench(): void {

		// Apply sidebar state as CSS class
		if (this.sideBarHidden) {
			this.workbench.addClass('nosidebar');
		}
1100 1101 1102
		if (this.panelHidden) {
			this.workbench.addClass('nopanel');
		}
E
Erich Gamma 已提交
1103

1104 1105
		this.setFontAliasing(this.fontAliasing);

B
Benjamin Pasero 已提交
1106
		// Apply title style if shown
1107 1108 1109 1110 1111 1112 1113 1114
		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 已提交
1115 1116
		}

E
Erich Gamma 已提交
1117
		// Create Parts
B
Benjamin Pasero 已提交
1118
		this.createTitlebarPart();
E
Erich Gamma 已提交
1119 1120 1121
		this.createActivityBarPart();
		this.createSidebarPart();
		this.createEditorPart();
1122
		this.createPanelPart();
E
Erich Gamma 已提交
1123 1124 1125 1126 1127 1128
		this.createStatusbarPart();

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

B
Benjamin Pasero 已提交
1129 1130 1131 1132 1133 1134 1135 1136 1137 1138
	private createTitlebarPart(): void {
		const titlebarContainer = $(this.workbench).div({
			'class': ['part', 'titlebar'],
			id: Identifiers.TITLEBAR_PART,
			role: 'contentinfo'
		});

		this.titlebarPart.create(titlebarContainer);
	}

E
Erich Gamma 已提交
1139
	private createActivityBarPart(): void {
B
Benjamin Pasero 已提交
1140
		const activitybarPartContainer = $(this.workbench)
E
Erich Gamma 已提交
1141 1142
			.div({
				'class': ['part', 'activitybar', this.sideBarPosition === Position.LEFT ? 'left' : 'right'],
1143 1144
				id: Identifiers.ACTIVITYBAR_PART,
				role: 'navigation'
E
Erich Gamma 已提交
1145 1146 1147 1148 1149 1150
			});

		this.activitybarPart.create(activitybarPartContainer);
	}

	private createSidebarPart(): void {
B
Benjamin Pasero 已提交
1151
		const sidebarPartContainer = $(this.workbench)
E
Erich Gamma 已提交
1152 1153
			.div({
				'class': ['part', 'sidebar', this.sideBarPosition === Position.LEFT ? 'left' : 'right'],
1154 1155
				id: Identifiers.SIDEBAR_PART,
				role: 'complementary'
E
Erich Gamma 已提交
1156 1157 1158 1159 1160
			});

		this.sidebarPart.create(sidebarPartContainer);
	}

I
isidor 已提交
1161
	private createPanelPart(): void {
B
Benjamin Pasero 已提交
1162
		const panelPartContainer = $(this.workbench)
I
isidor 已提交
1163
			.div({
1164
				'class': ['part', 'panel'],
1165 1166
				id: Identifiers.PANEL_PART,
				role: 'complementary'
I
isidor 已提交
1167 1168 1169 1170 1171
			});

		this.panelPart.create(panelPartContainer);
	}

E
Erich Gamma 已提交
1172
	private createEditorPart(): void {
B
Benjamin Pasero 已提交
1173
		const editorContainer = $(this.workbench)
E
Erich Gamma 已提交
1174
			.div({
1175
				'class': ['part', 'editor', 'empty'],
1176 1177
				id: Identifiers.EDITOR_PART,
				role: 'main'
E
Erich Gamma 已提交
1178 1179 1180 1181 1182 1183
			});

		this.editorPart.create(editorContainer);
	}

	private createStatusbarPart(): void {
B
Benjamin Pasero 已提交
1184
		const statusbarContainer = $(this.workbench).div({
E
Erich Gamma 已提交
1185
			'class': ['part', 'statusbar'],
1186 1187
			id: Identifiers.STATUSBAR_PART,
			role: 'contentinfo'
E
Erich Gamma 已提交
1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204
		});

		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 已提交
1205 1206 1207 1208 1209 1210
	public getPanelPart(): PanelPart {
		assert.ok(this.workbenchStarted, 'Workbench is not started. Call startup() first.');

		return this.panelPart;
	}

E
Erich Gamma 已提交
1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227
	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);
		}
	}
1228 1229 1230 1231

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

I
isidor 已提交
1233
	public toggleZenMode(skipLayout?: boolean): void {
I
isidor 已提交
1234 1235
		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
1236
		let toggleFullScreen = false;
I
isidor 已提交
1237
		if (this.zenMode.active) {
I
isidor 已提交
1238 1239
			const config = this.configurationService.getConfiguration<IZenModeSettings>('zenMode');
			toggleFullScreen = !browser.isFullscreen() && config.fullScreen;
I
isidor 已提交
1240
			this.zenMode.transitionedToFullScreen = toggleFullScreen;
1241 1242
			this.zenMode.wasSideBarVisible = this.isVisible(Parts.SIDEBAR_PART);
			this.zenMode.wasPanelVisible = this.isVisible(Parts.PANEL_PART);
1243
			this.setPanelHidden(true, true).done(undefined, errors.onUnexpectedError);
1244
			this.setSideBarHidden(true, true).done(undefined, errors.onUnexpectedError);
I
isidor 已提交
1245

1246 1247 1248
			if (config.hideActivityBar) {
				this.setActivityBarHidden(true, true);
			}
I
isidor 已提交
1249
			if (config.hideStatusBar) {
I
isidor 已提交
1250 1251
				this.setStatusBarHidden(true, true);
			}
I
isidor 已提交
1252
			if (config.hideTabs) {
I
isidor 已提交
1253 1254
				this.editorPart.hideTabs(true);
			}
1255
		} else {
1256
			if (this.zenMode.wasPanelVisible) {
1257
				this.setPanelHidden(false, true).done(undefined, errors.onUnexpectedError);
1258
			}
1259
			if (this.zenMode.wasSideBarVisible) {
1260
				this.setSideBarHidden(false, true).done(undefined, errors.onUnexpectedError);
1261
			}
1262 1263
			// Status bar and activity bar visibility come from settings -> update their visibility.
			this.onDidUpdateConfiguration(true);
I
isidor 已提交
1264
			this.editorPart.hideTabs(false);
I
isidor 已提交
1265 1266 1267 1268
			const activeEditor = this.editorPart.getActiveEditor();
			if (activeEditor) {
				activeEditor.focus();
			}
1269
			toggleFullScreen = this.zenMode.transitionedToFullScreen && browser.isFullscreen();
I
isidor 已提交
1270
		}
1271
		this.inZenMode.set(this.zenMode.active);
I
isidor 已提交
1272

I
isidor 已提交
1273
		if (!skipLayout) {
1274
			this.layout();
I
isidor 已提交
1275
		}
1276 1277 1278
		if (toggleFullScreen) {
			this.windowService.toggleFullScreen().done(undefined, errors.onUnexpectedError);
		}
I
isidor 已提交
1279 1280
	}

1281 1282 1283 1284 1285 1286 1287 1288 1289 1290
	// 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 已提交
1291
				return; // Cannot resize other parts
1292 1293 1294 1295
		}
	}


1296
	private shouldRestoreLastOpenedViewlet(): boolean {
1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307
		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 已提交
1308
}