workbench.ts 46.5 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
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 { 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 { ITextModelService } 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, inRecentFilesPickerContextKey } from "vs/workbench/electron-browser/actions";
96
import { KeyMod, KeyCode } from 'vs/base/common/keyCodes';
97 98
import { KeybindingsRegistry } from "vs/platform/keybinding/common/keybindingsRegistry";
import { getQuickNavigateHandler, inQuickOpenContext } from "vs/workbench/browser/parts/quickopen/quickopen";
E
Erich Gamma 已提交
99

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

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

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

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

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

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

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

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

157 158
	private _onTitleBarVisibilityChange: Emitter<void>;

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

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

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

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

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

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

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

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

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

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

E
Erich Gamma 已提交
256 257 258 259 260 261 262 263 264 265 266 267 268 269 270
	/**
	 * 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();

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

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

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

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

			// Settings
			this.initSettings();

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

			// Workbench Layout
			this.createWorkbenchLayout();

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

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

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

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

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

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

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

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

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

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

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

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

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

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

			// Rethrow
			throw error;
		}
	}

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

B
Benjamin Pasero 已提交
392
		// Actions registered here to adjust for developing vs built workbench
393 394
		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 已提交
395
		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 已提交
396
		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"));
397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418

		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 }
		});
419 420
	}

421
	private resolveEditorsToOpen(): TPromise<IResourceInputType[]> {
B
Benjamin Pasero 已提交
422 423

		// Files to open, diff or create
424 425
		if (this.hasFilesToCreateOpenOrDiff) {
			const wbopt = this.workbenchParams.options;
B
Benjamin Pasero 已提交
426 427 428
			const filesToCreate = wbopt.filesToCreate || [];
			const filesToOpen = wbopt.filesToOpen || [];
			const filesToDiff = wbopt.filesToDiff;
B
Benjamin Pasero 已提交
429 430

			// Files to diff is exclusive
431
			if (filesToDiff && filesToDiff.length === 2) {
432 433 434 435 436
				return TPromise.as([<IResourceDiffInput>{
					leftResource: filesToDiff[0].resource,
					rightResource: filesToDiff[1].resource,
					options: { pinned: true }
				}]);
B
Benjamin Pasero 已提交
437 438 439 440
			}

			// Otherwise: Open/Create files
			else {
441 442 443
				const filesToCreateInputs: IUntitledResourceInput[] = filesToCreate.map(resourceInput => {
					return <IUntitledResourceInput>{
						filePath: resourceInput.resource.fsPath,
444 445
						options: { pinned: true }
					};
B
Benjamin Pasero 已提交
446
				});
447

448
				return TPromise.as([].concat(filesToOpen).concat(filesToCreateInputs));
B
Benjamin Pasero 已提交
449 450 451
			}
		}

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

458 459 460 461 462
			return this.backupFileService.hasBackups().then(hasBackups => {
				if (hasBackups) {
					return TPromise.as([]); // do not open any empty untitled file if we have backups to restore
				}

463
				return TPromise.as([<IUntitledResourceInput>{}]);
464
			});
B
Benjamin Pasero 已提交
465 466 467 468 469
		}

		return TPromise.as([]);
	}

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

473
		this.toDispose.push(this.lifecycleService.onShutdown(this.shutdownComponents, this));
E
Erich Gamma 已提交
474 475

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

478 479 480
		// Clipboard
		serviceCollection.set(IClipboardService, new ClipboardService());

481 482 483 484 485 486
		// 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);

487 488 489
		// Progress 2
		serviceCollection.set(IProgressService2, new SyncDescriptor(ProgressService2));

490
		// Keybindings
A
Alex Dima 已提交
491
		this.contextKeyService = this.instantiationService.createInstance(ContextKeyService);
492
		serviceCollection.set(IContextKeyService, this.contextKeyService);
493

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

497 498 499
		// List
		serviceCollection.set(IListService, this.instantiationService.createInstance(ListService));

500
		// Context Menu
501
		serviceCollection.set(IContextMenuService, new SyncDescriptor(ContextMenuService));
502

503 504
		// Menus/Actions
		serviceCollection.set(IMenuService, new SyncDescriptor(MenuService));
505

P
Pine Wu 已提交
506
		// Sidebar part
507
		this.sidebarPart = this.instantiationService.createInstance(SidebarPart, Identifiers.SIDEBAR_PART);
E
Erich Gamma 已提交
508 509
		this.toDispose.push(this.sidebarPart);
		this.toShutdown.push(this.sidebarPart);
P
Pine Wu 已提交
510 511 512 513

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

I
isidor 已提交
515
		// Panel service (panel part)
516
		this.panelPart = this.instantiationService.createInstance(PanelPart, Identifiers.PANEL_PART);
I
isidor 已提交
517 518
		this.toDispose.push(this.panelPart);
		this.toShutdown.push(this.panelPart);
519
		serviceCollection.set(IPanelService, this.panelPart);
I
isidor 已提交
520

E
Erich Gamma 已提交
521
		// Activity service (activitybar part)
522
		this.activitybarPart = this.instantiationService.createInstance(ActivitybarPart, Identifiers.ACTIVITYBAR_PART);
E
Erich Gamma 已提交
523 524
		this.toDispose.push(this.activitybarPart);
		this.toShutdown.push(this.activitybarPart);
525
		serviceCollection.set(IActivityBarService, this.activitybarPart);
E
Erich Gamma 已提交
526 527

		// Editor service (editor part)
528
		this.editorPart = this.instantiationService.createInstance(EditorPart, Identifiers.EDITOR_PART, !this.hasFilesToCreateOpenOrDiff);
E
Erich Gamma 已提交
529 530
		this.toDispose.push(this.editorPart);
		this.toShutdown.push(this.editorPart);
531
		this.editorService = this.instantiationService.createInstance(WorkbenchEditorService, this.editorPart);
532
		serviceCollection.set(IWorkbenchEditorService, this.editorService);
533
		serviceCollection.set(IEditorGroupService, this.editorPart);
E
Erich Gamma 已提交
534

535 536 537 538 539 540
		// 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);

541
		// File Service
542 543 544
		const fileService = this.instantiationService.createInstance(FileService);
		serviceCollection.set(IFileService, fileService);
		this.toDispose.push(fileService.onFileChanges(e => this.configurationService.handleWorkspaceFileEvents(e)));
545

546
		// History
547
		serviceCollection.set(IHistoryService, new SyncDescriptor(HistoryService));
548

549
		// Backup File Service
550
		this.backupFileService = this.instantiationService.createInstance(BackupFileService, this.workbenchParams.configuration.backupPath);
551
		serviceCollection.set(IBackupFileService, this.backupFileService);
552

553
		// Text File Service
554
		serviceCollection.set(ITextFileService, new SyncDescriptor(TextFileService));
555

J
Joao Moreno 已提交
556
		// SCM Service
557
		serviceCollection.set(ISCMService, new SyncDescriptor(SCMService));
558

B
Benjamin Pasero 已提交
559
		// Text Model Resolver Service
560
		serviceCollection.set(ITextModelService, new SyncDescriptor(TextModelResolverService));
B
Benjamin Pasero 已提交
561

562
		// Configuration Editing
563 564
		this.configurationEditingService = this.instantiationService.createInstance(ConfigurationEditingService);
		serviceCollection.set(IConfigurationEditingService, this.configurationEditingService);
565

566 567 568
		// Keybinding Editing
		serviceCollection.set(IKeybindingEditingService, this.instantiationService.createInstance(KeybindingsEditingService));

569
		// Configuration Resolver
570
		const workspace = this.contextService.getWorkspace();
571
		serviceCollection.set(IConfigurationResolverService, new SyncDescriptor(ConfigurationResolverService, workspace ? workspace.resource : null, process.env));
572

E
Erich Gamma 已提交
573
		// Quick open service (quick open controller)
574
		this.quickOpen = this.instantiationService.createInstance(QuickOpenController);
E
Erich Gamma 已提交
575 576
		this.toDispose.push(this.quickOpen);
		this.toShutdown.push(this.quickOpen);
577
		serviceCollection.set(IQuickOpenService, this.quickOpen);
E
Erich Gamma 已提交
578

B
polish  
Benjamin Pasero 已提交
579
		// Contributed services
B
Benjamin Pasero 已提交
580
		const contributedServices = getServices();
E
Erich Gamma 已提交
581
		for (let contributedService of contributedServices) {
582
			serviceCollection.set(contributedService.id, contributedService.descriptor);
E
Erich Gamma 已提交
583 584 585
		}

		// Set the some services to registries that have been created eagerly
586 587 588
		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 已提交
589 590 591 592 593
	}

	private initSettings(): void {

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

I
isidor 已提交
596
		// Panel part visibility
597
		const panelRegistry = Registry.as<PanelRegistry>(PanelExtensions.Panels);
B
Benjamin Pasero 已提交
598
		this.panelHidden = this.storageService.getBoolean(Workbench.panelHiddenSettingKey, StorageScope.WORKSPACE, true);
599 600
		if (!panelRegistry.getDefaultPanelId()) {
			this.panelHidden = true; // we hide panel part if there is no default panel
I
isidor 已提交
601
		}
I
isidor 已提交
602

E
Erich Gamma 已提交
603
		// Sidebar position
604 605
		const sideBarPosition = this.configurationService.lookup<string>(Workbench.sidebarPositionConfigurationKey).value;
		this.sideBarPosition = (sideBarPosition === 'right') ? Position.RIGHT : Position.LEFT;
B
Benjamin Pasero 已提交
606 607

		// Statusbar visibility
608 609
		const statusBarVisible = this.configurationService.lookup<string>(Workbench.statusbarVisibleConfigurationKey).value;
		this.statusBarHidden = !statusBarVisible;
S
Sanders Lauture 已提交
610 611 612 613

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

I
isidor 已提交
615 616
		// Zen mode
		this.zenMode = {
I
isidor 已提交
617
			active: false,
618 619 620
			transitionedToFullScreen: false,
			wasSideBarVisible: false,
			wasPanelVisible: false
I
isidor 已提交
621
		};
E
Erich Gamma 已提交
622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642
	}

	/**
	 * 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 已提交
643
		const activeElement = document.activeElement;
E
Erich Gamma 已提交
644 645 646 647
		if (!activeElement) {
			return false;
		}

648 649 650 651 652
		const container = this.getContainer(part);
		return DOM.isAncestor(activeElement, container);
	}

	public getContainer(part: Parts): HTMLElement {
E
Erich Gamma 已提交
653 654
		let container: Builder = null;
		switch (part) {
B
Benjamin Pasero 已提交
655 656 657
			case Parts.TITLEBAR_PART:
				container = this.titlebarPart.getContainer();
				break;
E
Erich Gamma 已提交
658 659 660 661 662 663
			case Parts.ACTIVITYBAR_PART:
				container = this.activitybarPart.getContainer();
				break;
			case Parts.SIDEBAR_PART:
				container = this.sidebarPart.getContainer();
				break;
I
isidor 已提交
664 665 666
			case Parts.PANEL_PART:
				container = this.panelPart.getContainer();
				break;
E
Erich Gamma 已提交
667 668 669 670 671 672 673
			case Parts.EDITOR_PART:
				container = this.editorPart.getContainer();
				break;
			case Parts.STATUSBAR_PART:
				container = this.statusbarPart.getContainer();
				break;
		}
674
		return container && container.getHTMLElement();
E
Erich Gamma 已提交
675 676 677
	}

	public isVisible(part: Parts): boolean {
B
Benjamin Pasero 已提交
678
		switch (part) {
B
Benjamin Pasero 已提交
679
			case Parts.TITLEBAR_PART:
680
				return this.getCustomTitleBarStyle() && !browser.isFullscreen();
B
Benjamin Pasero 已提交
681
			case Parts.SIDEBAR_PART:
682
				return !this.sideBarHidden;
B
Benjamin Pasero 已提交
683
			case Parts.PANEL_PART:
684
				return !this.panelHidden;
B
Benjamin Pasero 已提交
685
			case Parts.STATUSBAR_PART:
686
				return !this.statusBarHidden;
S
Sanders Lauture 已提交
687
			case Parts.ACTIVITYBAR_PART:
688
				return !this.activityBarHidden;
689
		}
E
Erich Gamma 已提交
690 691 692 693

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

694 695
	public getTitleBarOffset(): number {
		let offset = 0;
696
		if (this.isVisible(Parts.TITLEBAR_PART)) {
697 698 699 700 701 702
			offset = 22 / browser.getZoomFactor(); // adjust the position based on title bar size and zoom factor
		}

		return offset;
	}

703
	private getCustomTitleBarStyle(): 'custom' {
B
Benjamin Pasero 已提交
704
		if (!isMacintosh) {
705
			return null; // custom title bar is only supported on Mac currently
B
Benjamin Pasero 已提交
706 707
		}

708
		const isDev = !this.environmentService.isBuilt || this.environmentService.isExtensionDevelopment;
B
Benjamin Pasero 已提交
709
		if (isDev) {
710
			return null; // not enabled when developing due to https://github.com/electron/electron/issues/3647
B
Benjamin Pasero 已提交
711 712
		}

713
		const windowConfig = this.configurationService.getConfiguration<IWindowSettings>();
714 715 716 717 718
		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 已提交
719

720 721 722 723
			const style = windowConfig.window.titleBarStyle;
			if (style === 'custom') {
				return style;
			}
724 725 726
		}

		return null;
B
Benjamin Pasero 已提交
727 728
	}

729
	private setStatusBarHidden(hidden: boolean, skipLayout?: boolean): void {
730 731
		this.statusBarHidden = hidden;

I
isidor 已提交
732

733 734
		// Layout
		if (!skipLayout) {
735
			this.workbenchLayout.layout();
736 737 738
		}
	}

S
Sanders Lauture 已提交
739 740 741
	public setActivityBarHidden(hidden: boolean, skipLayout?: boolean): void {
		this.activityBarHidden = hidden;

I
isidor 已提交
742

S
Sanders Lauture 已提交
743 744
		// Layout
		if (!skipLayout) {
745
			this.workbenchLayout.layout();
S
Sanders Lauture 已提交
746 747 748
		}
	}

749
	public setSideBarHidden(hidden: boolean, skipLayout?: boolean): TPromise<void> {
E
Erich Gamma 已提交
750 751 752 753 754 755 756 757 758
		this.sideBarHidden = hidden;

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

B
Benjamin Pasero 已提交
759
		// If sidebar becomes hidden, also hide the current active Viewlet if any
B
Benjamin Pasero 已提交
760
		let promise = TPromise.as<any>(null);
E
Erich Gamma 已提交
761
		if (hidden && this.sidebarPart.getActiveViewlet()) {
762 763 764
			promise = this.sidebarPart.hideActiveViewlet().then(() => {
				const activeEditor = this.editorPart.getActiveEditor();
				const activePanel = this.panelPart.getActivePanel();
B
Benjamin Pasero 已提交
765

766 767 768 769 770 771 772
				// 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 已提交
773 774
		}

B
Benjamin Pasero 已提交
775
		// If sidebar becomes visible, show last active Viewlet or default viewlet
E
Erich Gamma 已提交
776
		else if (!hidden && !this.sidebarPart.getActiveViewlet()) {
777
			const viewletToOpen = this.sidebarPart.getLastActiveViewletId();
E
Erich Gamma 已提交
778
			if (viewletToOpen) {
779
				promise = this.sidebarPart.openViewlet(viewletToOpen, true);
E
Erich Gamma 已提交
780 781 782
			}
		}

783
		return promise.then(() => {
784

785
			// Remember in settings
786 787 788 789 790 791
			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);
			}
792 793 794

			// Layout
			if (!skipLayout) {
795
				this.workbenchLayout.layout();
796 797
			}
		});
E
Erich Gamma 已提交
798 799
	}

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

803 804 805 806 807 808 809
		// Adjust CSS
		if (hidden) {
			this.workbench.addClass('nopanel');
		} else {
			this.workbench.removeClass('nopanel');
		}

I
isidor 已提交
810
		// If panel part becomes hidden, also hide the current active panel if any
811
		let promise = TPromise.as<any>(null);
I
isidor 已提交
812
		if (hidden && this.panelPart.getActivePanel()) {
813 814 815 816 817 818 819
			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 已提交
820 821 822 823
		}

		// If panel part becomes visible, show last active panel or default panel
		else if (!hidden && !this.panelPart.getActivePanel()) {
824
			const panelToOpen = this.panelPart.getLastActivePanelId();
I
isidor 已提交
825
			if (panelToOpen) {
826
				promise = this.panelPart.openPanel(panelToOpen, true);
I
isidor 已提交
827 828 829
			}
		}

830
		return promise.then(() => {
831

832
			// Remember in settings
833 834 835 836 837
			if (!hidden) {
				this.storageService.store(Workbench.panelHiddenSettingKey, 'false', StorageScope.WORKSPACE);
			} else {
				this.storageService.remove(Workbench.panelHiddenSettingKey, StorageScope.WORKSPACE);
			}
838 839 840

			// Layout
			if (!skipLayout) {
841
				this.workbenchLayout.layout();
842 843
			}
		});
I
isidor 已提交
844 845
	}

I
isidor 已提交
846
	public toggleMaximizedPanel(): void {
847
		this.workbenchLayout.layout({ toggleMaximizedPanel: true });
I
isidor 已提交
848 849
	}

I
isidor 已提交
850 851 852 853
	public isPanelMaximized(): boolean {
		return this.workbenchLayout.isPanelMaximized();
	}

E
Erich Gamma 已提交
854 855 856 857
	public getSideBarPosition(): Position {
		return this.sideBarPosition;
	}

858
	private setSideBarPosition(position: Position): void {
E
Erich Gamma 已提交
859
		if (this.sideBarHidden) {
860
			this.setSideBarHidden(false, true /* Skip Layout */).done(undefined, errors.onUnexpectedError);
E
Erich Gamma 已提交
861 862
		}

B
Benjamin Pasero 已提交
863 864
		const newPositionValue = (position === Position.LEFT) ? 'left' : 'right';
		const oldPositionValue = (this.sideBarPosition === Position.LEFT) ? 'left' : 'right';
E
Erich Gamma 已提交
865 866 867 868 869 870 871 872
		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);

873 874 875 876
		// Update Styles
		this.activitybarPart.updateStyles();
		this.sidebarPart.updateStyles();

E
Erich Gamma 已提交
877
		// Layout
878
		this.workbenchLayout.layout();
E
Erich Gamma 已提交
879 880
	}

B
Benjamin Pasero 已提交
881
	public dispose(): void {
E
Erich Gamma 已提交
882
		if (this.isStarted()) {
B
Benjamin Pasero 已提交
883
			this.shutdownComponents();
E
Erich Gamma 已提交
884 885 886
			this.workbenchShutdown = true;
		}

J
Joao Moreno 已提交
887
		this.toDispose = dispose(this.toDispose);
E
Erich Gamma 已提交
888 889 890 891 892 893
	}

	/**
	 * 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 已提交
894
	public layout(options?: ILayoutOptions): void {
E
Erich Gamma 已提交
895
		if (this.isStarted()) {
B
Benjamin Pasero 已提交
896
			this.workbenchLayout.layout(options);
E
Erich Gamma 已提交
897 898 899
		}
	}

900 901 902 903 904 905
	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 已提交
906

I
isidor 已提交
907
		// Preserve zen mode only on reload. Real quit gets out of zen mode so novice users do not get stuck in zen mode.
908 909 910 911 912 913 914
		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 已提交
915 916 917 918 919 920 921 922

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

	private registerListeners(): void {

		// Listen to editor changes
923
		this.toDispose.push(this.editorPart.onEditorsChanged(() => this.onEditorsChanged()));
924 925

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

929 930 931 932 933
		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()));
934 935 936 937 938 939 940 941 942 943

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

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

944
		// Apply as CSS class
945 946 947 948 949
		const isFullscreen = browser.isFullscreen();
		if (isFullscreen) {
			this.addClass('fullscreen');
		} else {
			this.removeClass('fullscreen');
I
isidor 已提交
950 951
			if (this.zenMode.transitionedToFullScreen && this.zenMode.active) {
				this.toggleZenMode();
I
isidor 已提交
952
			}
953
		}
954

955 956 957 958 959
		// 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
960
		}
E
Erich Gamma 已提交
961 962
	}

963
	private onEditorsChanged(): void {
B
Benjamin Pasero 已提交
964
		const visibleEditors = this.editorService.getVisibleEditors().length;
E
Erich Gamma 已提交
965 966 967 968

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

969
		const editorContainer = this.editorPart.getContainer();
E
Erich Gamma 已提交
970
		if (visibleEditors === 0) {
971
			this.editorsVisibleContext.reset();
972
			this.editorBackgroundDelayer.trigger(() => editorContainer.addClass('empty'));
E
Erich Gamma 已提交
973
		} else {
974
			this.editorsVisibleContext.set(true);
975
			this.editorBackgroundDelayer.trigger(() => editorContainer.removeClass('empty'));
E
Erich Gamma 已提交
976 977 978
		}
	}

979
	private onDidUpdateConfiguration(skipLayout?: boolean): void {
980
		const newSidebarPositionValue = this.configurationService.lookup<string>(Workbench.sidebarPositionConfigurationKey).value;
981
		const newSidebarPosition = (newSidebarPositionValue === 'right') ? Position.RIGHT : Position.LEFT;
982 983 984
		if (newSidebarPosition !== this.getSideBarPosition()) {
			this.setSideBarPosition(newSidebarPosition);
		}
985

986 987 988 989 990
		if (!this.zenMode.active) {
			const newStatusbarHiddenValue = !this.configurationService.lookup<boolean>(Workbench.statusbarVisibleConfigurationKey).value;
			if (newStatusbarHiddenValue !== this.statusBarHidden) {
				this.setStatusBarHidden(newStatusbarHiddenValue, skipLayout);
			}
S
Sanders Lauture 已提交
991

992 993 994 995
			const newActivityBarHiddenValue = !this.configurationService.lookup<boolean>(Workbench.activityBarVisibleConfigurationKey).value;
			if (newActivityBarHiddenValue !== this.activityBarHidden) {
				this.setActivityBarHidden(newActivityBarHiddenValue, skipLayout);
			}
S
Sanders Lauture 已提交
996
		}
997 998
	}

E
Erich Gamma 已提交
999 1000 1001 1002
	private createWorkbenchLayout(): void {
		this.workbenchLayout = this.instantiationService.createInstance(WorkbenchLayout,
			$(this.container),							// Parent
			this.workbench,								// Workbench Container
I
isidor 已提交
1003
			{
B
Benjamin Pasero 已提交
1004
				titlebar: this.titlebarPart,			// Title Bar
I
isidor 已提交
1005 1006 1007 1008 1009 1010
				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 已提交
1011
			this.quickOpen								// Quickopen
E
Erich Gamma 已提交
1012 1013 1014 1015 1016 1017 1018 1019 1020
		);

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

	private createWorkbench(): void {

		// Create Workbench DIV Off-DOM
		this.workbenchContainer = $('.monaco-workbench-container');
1021
		this.workbench = $().div({ 'class': 'monaco-workbench ' + (isWindows ? 'windows' : isLinux ? 'linux' : 'mac'), id: Identifiers.WORKBENCH_CONTAINER }).appendTo(this.workbenchContainer);
E
Erich Gamma 已提交
1022 1023 1024 1025 1026 1027 1028 1029
	}

	private renderWorkbench(): void {

		// Apply sidebar state as CSS class
		if (this.sideBarHidden) {
			this.workbench.addClass('nosidebar');
		}
1030 1031 1032
		if (this.panelHidden) {
			this.workbench.addClass('nopanel');
		}
E
Erich Gamma 已提交
1033

B
Benjamin Pasero 已提交
1034
		// Apply title style if shown
1035 1036 1037 1038 1039 1040 1041 1042
		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 已提交
1043 1044
		}

E
Erich Gamma 已提交
1045
		// Create Parts
B
Benjamin Pasero 已提交
1046
		this.createTitlebarPart();
E
Erich Gamma 已提交
1047 1048 1049
		this.createActivityBarPart();
		this.createSidebarPart();
		this.createEditorPart();
1050
		this.createPanelPart();
E
Erich Gamma 已提交
1051 1052 1053 1054 1055 1056
		this.createStatusbarPart();

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

B
Benjamin Pasero 已提交
1057 1058 1059 1060 1061 1062 1063 1064 1065 1066
	private createTitlebarPart(): void {
		const titlebarContainer = $(this.workbench).div({
			'class': ['part', 'titlebar'],
			id: Identifiers.TITLEBAR_PART,
			role: 'contentinfo'
		});

		this.titlebarPart.create(titlebarContainer);
	}

E
Erich Gamma 已提交
1067
	private createActivityBarPart(): void {
B
Benjamin Pasero 已提交
1068
		const activitybarPartContainer = $(this.workbench)
E
Erich Gamma 已提交
1069 1070
			.div({
				'class': ['part', 'activitybar', this.sideBarPosition === Position.LEFT ? 'left' : 'right'],
1071 1072
				id: Identifiers.ACTIVITYBAR_PART,
				role: 'navigation'
E
Erich Gamma 已提交
1073 1074 1075 1076 1077 1078
			});

		this.activitybarPart.create(activitybarPartContainer);
	}

	private createSidebarPart(): void {
B
Benjamin Pasero 已提交
1079
		const sidebarPartContainer = $(this.workbench)
E
Erich Gamma 已提交
1080 1081
			.div({
				'class': ['part', 'sidebar', this.sideBarPosition === Position.LEFT ? 'left' : 'right'],
1082 1083
				id: Identifiers.SIDEBAR_PART,
				role: 'complementary'
E
Erich Gamma 已提交
1084 1085 1086 1087 1088
			});

		this.sidebarPart.create(sidebarPartContainer);
	}

I
isidor 已提交
1089
	private createPanelPart(): void {
B
Benjamin Pasero 已提交
1090
		const panelPartContainer = $(this.workbench)
I
isidor 已提交
1091
			.div({
1092
				'class': ['part', 'panel'],
1093 1094
				id: Identifiers.PANEL_PART,
				role: 'complementary'
I
isidor 已提交
1095 1096 1097 1098 1099
			});

		this.panelPart.create(panelPartContainer);
	}

E
Erich Gamma 已提交
1100
	private createEditorPart(): void {
B
Benjamin Pasero 已提交
1101
		const editorContainer = $(this.workbench)
E
Erich Gamma 已提交
1102
			.div({
1103
				'class': ['part', 'editor', 'empty'],
1104 1105
				id: Identifiers.EDITOR_PART,
				role: 'main'
E
Erich Gamma 已提交
1106 1107 1108 1109 1110 1111
			});

		this.editorPart.create(editorContainer);
	}

	private createStatusbarPart(): void {
B
Benjamin Pasero 已提交
1112
		const statusbarContainer = $(this.workbench).div({
E
Erich Gamma 已提交
1113
			'class': ['part', 'statusbar'],
1114 1115
			id: Identifiers.STATUSBAR_PART,
			role: 'contentinfo'
E
Erich Gamma 已提交
1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132
		});

		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 已提交
1133 1134 1135 1136 1137 1138
	public getPanelPart(): PanelPart {
		assert.ok(this.workbenchStarted, 'Workbench is not started. Call startup() first.');

		return this.panelPart;
	}

E
Erich Gamma 已提交
1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155
	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);
		}
	}
1156 1157 1158 1159

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

I
isidor 已提交
1161
	public toggleZenMode(skipLayout?: boolean): void {
I
isidor 已提交
1162 1163
		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
1164
		let toggleFullScreen = false;
I
isidor 已提交
1165
		if (this.zenMode.active) {
I
isidor 已提交
1166 1167
			const config = this.configurationService.getConfiguration<IZenModeSettings>('zenMode');
			toggleFullScreen = !browser.isFullscreen() && config.fullScreen;
I
isidor 已提交
1168
			this.zenMode.transitionedToFullScreen = toggleFullScreen;
1169 1170
			this.zenMode.wasSideBarVisible = this.isVisible(Parts.SIDEBAR_PART);
			this.zenMode.wasPanelVisible = this.isVisible(Parts.PANEL_PART);
1171
			this.setPanelHidden(true, true).done(undefined, errors.onUnexpectedError);
1172
			this.setSideBarHidden(true, true).done(undefined, errors.onUnexpectedError);
I
isidor 已提交
1173

1174 1175 1176
			if (config.hideActivityBar) {
				this.setActivityBarHidden(true, true);
			}
I
isidor 已提交
1177
			if (config.hideStatusBar) {
I
isidor 已提交
1178 1179
				this.setStatusBarHidden(true, true);
			}
I
isidor 已提交
1180
			if (config.hideTabs) {
I
isidor 已提交
1181 1182
				this.editorPart.hideTabs(true);
			}
1183
		} else {
1184
			if (this.zenMode.wasPanelVisible) {
1185
				this.setPanelHidden(false, true).done(undefined, errors.onUnexpectedError);
1186
			}
1187
			if (this.zenMode.wasSideBarVisible) {
1188
				this.setSideBarHidden(false, true).done(undefined, errors.onUnexpectedError);
1189
			}
1190 1191
			// Status bar and activity bar visibility come from settings -> update their visibility.
			this.onDidUpdateConfiguration(true);
I
isidor 已提交
1192
			this.editorPart.hideTabs(false);
I
isidor 已提交
1193 1194 1195 1196
			const activeEditor = this.editorPart.getActiveEditor();
			if (activeEditor) {
				activeEditor.focus();
			}
1197
			toggleFullScreen = this.zenMode.transitionedToFullScreen && browser.isFullscreen();
I
isidor 已提交
1198
		}
1199
		this.inZenMode.set(this.zenMode.active);
I
isidor 已提交
1200

I
isidor 已提交
1201
		if (!skipLayout) {
1202
			this.layout();
I
isidor 已提交
1203
		}
1204 1205 1206
		if (toggleFullScreen) {
			this.windowService.toggleFullScreen().done(undefined, errors.onUnexpectedError);
		}
I
isidor 已提交
1207 1208
	}

1209 1210 1211 1212 1213 1214 1215 1216 1217 1218
	// 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 已提交
1219
				return; // Cannot resize other parts
1220 1221 1222 1223
		}
	}


1224
	private shouldRestoreLastOpenedViewlet(): boolean {
1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235
		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 已提交
1236
}