workbench.ts 46.4 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 453
		// Empty workbench
		else if (!this.contextService.hasWorkspace() && this.openUntitledFile()) {
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([]);
	}

470
	private openUntitledFile() {
C
Christof Marti 已提交
471
		return !this.configurationService.lookup('workbench.welcome.enabled').value;
472 473
	}

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

477
		this.toDispose.push(this.lifecycleService.onShutdown(this.shutdownComponents, this));
E
Erich Gamma 已提交
478 479

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

482 483 484
		// Clipboard
		serviceCollection.set(IClipboardService, new ClipboardService());

485 486 487 488 489 490
		// 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);

491 492 493
		// Progress 2
		serviceCollection.set(IProgressService2, new SyncDescriptor(ProgressService2));

494
		// Keybindings
A
Alex Dima 已提交
495
		this.contextKeyService = this.instantiationService.createInstance(ContextKeyService);
496
		serviceCollection.set(IContextKeyService, this.contextKeyService);
497

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

501 502 503
		// List
		serviceCollection.set(IListService, this.instantiationService.createInstance(ListService));

504
		// Context Menu
505
		serviceCollection.set(IContextMenuService, new SyncDescriptor(ContextMenuService));
506

507 508
		// Menus/Actions
		serviceCollection.set(IMenuService, new SyncDescriptor(MenuService));
509

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

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

I
isidor 已提交
519
		// Panel service (panel part)
520
		this.panelPart = this.instantiationService.createInstance(PanelPart, Identifiers.PANEL_PART);
I
isidor 已提交
521 522
		this.toDispose.push(this.panelPart);
		this.toShutdown.push(this.panelPart);
523
		serviceCollection.set(IPanelService, this.panelPart);
I
isidor 已提交
524

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

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

539 540 541 542 543 544
		// 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);

545
		// File Service
546 547 548
		const fileService = this.instantiationService.createInstance(FileService);
		serviceCollection.set(IFileService, fileService);
		this.toDispose.push(fileService.onFileChanges(e => this.configurationService.handleWorkspaceFileEvents(e)));
549

550
		// History
551
		serviceCollection.set(IHistoryService, new SyncDescriptor(HistoryService));
552

553
		// Backup File Service
554
		this.backupFileService = this.instantiationService.createInstance(BackupFileService, this.workbenchParams.configuration.backupPath);
555
		serviceCollection.set(IBackupFileService, this.backupFileService);
556

557
		// Text File Service
558
		serviceCollection.set(ITextFileService, new SyncDescriptor(TextFileService));
559

J
Joao Moreno 已提交
560
		// SCM Service
561
		serviceCollection.set(ISCMService, new SyncDescriptor(SCMService));
562

B
Benjamin Pasero 已提交
563
		// Text Model Resolver Service
564
		serviceCollection.set(ITextModelService, new SyncDescriptor(TextModelResolverService));
B
Benjamin Pasero 已提交
565

566
		// Configuration Editing
567 568
		this.configurationEditingService = this.instantiationService.createInstance(ConfigurationEditingService);
		serviceCollection.set(IConfigurationEditingService, this.configurationEditingService);
569

570 571 572
		// Keybinding Editing
		serviceCollection.set(IKeybindingEditingService, this.instantiationService.createInstance(KeybindingsEditingService));

573
		// Configuration Resolver
574
		const workspace = this.contextService.getWorkspace();
575
		serviceCollection.set(IConfigurationResolverService, new SyncDescriptor(ConfigurationResolverService, workspace ? workspace.resource : null, process.env));
576

E
Erich Gamma 已提交
577
		// Quick open service (quick open controller)
578
		this.quickOpen = this.instantiationService.createInstance(QuickOpenController);
E
Erich Gamma 已提交
579 580
		this.toDispose.push(this.quickOpen);
		this.toShutdown.push(this.quickOpen);
581
		serviceCollection.set(IQuickOpenService, this.quickOpen);
E
Erich Gamma 已提交
582

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

		// Set the some services to registries that have been created eagerly
590 591 592
		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 已提交
593 594 595 596 597
	}

	private initSettings(): void {

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

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

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

		// Statusbar visibility
612 613
		const statusBarVisible = this.configurationService.lookup<string>(Workbench.statusbarVisibleConfigurationKey).value;
		this.statusBarHidden = !statusBarVisible;
S
Sanders Lauture 已提交
614 615 616 617

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

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

	/**
	 * 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 已提交
647
		const activeElement = document.activeElement;
E
Erich Gamma 已提交
648 649 650 651
		if (!activeElement) {
			return false;
		}

652 653 654 655 656
		const container = this.getContainer(part);
		return DOM.isAncestor(activeElement, container);
	}

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

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

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

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

		return offset;
	}

707
	private getCustomTitleBarStyle(): 'custom' {
B
Benjamin Pasero 已提交
708
		if (!isMacintosh) {
709
			return null; // custom title bar is only supported on Mac currently
B
Benjamin Pasero 已提交
710 711
		}

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

717
		const windowConfig = this.configurationService.getConfiguration<IWindowSettings>();
718 719 720 721 722
		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 已提交
723

724 725 726 727
			const style = windowConfig.window.titleBarStyle;
			if (style === 'custom') {
				return style;
			}
728 729 730
		}

		return null;
B
Benjamin Pasero 已提交
731 732
	}

733
	private setStatusBarHidden(hidden: boolean, skipLayout?: boolean): void {
734 735
		this.statusBarHidden = hidden;

I
isidor 已提交
736

737 738
		// Layout
		if (!skipLayout) {
739
			this.workbenchLayout.layout();
740 741 742
		}
	}

S
Sanders Lauture 已提交
743 744 745
	public setActivityBarHidden(hidden: boolean, skipLayout?: boolean): void {
		this.activityBarHidden = hidden;

I
isidor 已提交
746

S
Sanders Lauture 已提交
747 748
		// Layout
		if (!skipLayout) {
749
			this.workbenchLayout.layout();
S
Sanders Lauture 已提交
750 751 752
		}
	}

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

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

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

770 771 772 773 774 775 776
				// 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 已提交
777 778
		}

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

787
		return promise.then(() => {
788

789
			// Remember in settings
790 791 792 793 794 795
			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);
			}
796 797 798

			// Layout
			if (!skipLayout) {
799
				this.workbenchLayout.layout();
800 801
			}
		});
E
Erich Gamma 已提交
802 803
	}

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

807 808 809 810 811 812 813
		// Adjust CSS
		if (hidden) {
			this.workbench.addClass('nopanel');
		} else {
			this.workbench.removeClass('nopanel');
		}

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

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

834
		return promise.then(() => {
835

836
			// Remember in settings
837 838 839 840 841
			if (!hidden) {
				this.storageService.store(Workbench.panelHiddenSettingKey, 'false', StorageScope.WORKSPACE);
			} else {
				this.storageService.remove(Workbench.panelHiddenSettingKey, StorageScope.WORKSPACE);
			}
842 843 844

			// Layout
			if (!skipLayout) {
845
				this.workbenchLayout.layout();
846 847
			}
		});
I
isidor 已提交
848 849
	}

I
isidor 已提交
850
	public toggleMaximizedPanel(): void {
851
		this.workbenchLayout.layout({ toggleMaximizedPanel: true });
I
isidor 已提交
852 853
	}

I
isidor 已提交
854 855 856 857
	public isPanelMaximized(): boolean {
		return this.workbenchLayout.isPanelMaximized();
	}

E
Erich Gamma 已提交
858 859 860 861
	public getSideBarPosition(): Position {
		return this.sideBarPosition;
	}

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

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

877 878 879 880
		// Update Styles
		this.activitybarPart.updateStyles();
		this.sidebarPart.updateStyles();

E
Erich Gamma 已提交
881
		// Layout
882
		this.workbenchLayout.layout();
E
Erich Gamma 已提交
883 884
	}

B
Benjamin Pasero 已提交
885
	public dispose(): void {
E
Erich Gamma 已提交
886
		if (this.isStarted()) {
B
Benjamin Pasero 已提交
887
			this.shutdownComponents();
E
Erich Gamma 已提交
888 889 890
			this.workbenchShutdown = true;
		}

J
Joao Moreno 已提交
891
		this.toDispose = dispose(this.toDispose);
E
Erich Gamma 已提交
892 893 894 895 896 897
	}

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

904 905 906 907 908 909
	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 已提交
910

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

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

	private registerListeners(): void {

		// Listen to editor changes
927
		this.toDispose.push(this.editorPart.onEditorsChanged(() => this.onEditorsChanged()));
928 929

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

933 934 935 936 937
		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()));
938 939 940 941 942 943 944 945 946 947

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

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

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

959 960 961 962 963
		// 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
964
		}
E
Erich Gamma 已提交
965 966
	}

967
	private onEditorsChanged(): void {
B
Benjamin Pasero 已提交
968
		const visibleEditors = this.editorService.getVisibleEditors().length;
E
Erich Gamma 已提交
969 970 971 972

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

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

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

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

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

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

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

	private createWorkbench(): void {

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

	private renderWorkbench(): void {

		// Apply sidebar state as CSS class
		if (this.sideBarHidden) {
			this.workbench.addClass('nosidebar');
		}
1034 1035 1036
		if (this.panelHidden) {
			this.workbench.addClass('nopanel');
		}
E
Erich Gamma 已提交
1037

B
Benjamin Pasero 已提交
1038
		// Apply title style if shown
1039 1040 1041 1042 1043 1044 1045 1046
		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 已提交
1047 1048
		}

E
Erich Gamma 已提交
1049
		// Create Parts
B
Benjamin Pasero 已提交
1050
		this.createTitlebarPart();
E
Erich Gamma 已提交
1051 1052 1053
		this.createActivityBarPart();
		this.createSidebarPart();
		this.createEditorPart();
1054
		this.createPanelPart();
E
Erich Gamma 已提交
1055 1056 1057 1058 1059 1060
		this.createStatusbarPart();

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

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

		this.titlebarPart.create(titlebarContainer);
	}

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

		this.activitybarPart.create(activitybarPartContainer);
	}

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

		this.sidebarPart.create(sidebarPartContainer);
	}

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

		this.panelPart.create(panelPartContainer);
	}

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

		this.editorPart.create(editorContainer);
	}

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

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

		return this.panelPart;
	}

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

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

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

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

I
isidor 已提交
1205
		if (!skipLayout) {
1206
			this.layout();
I
isidor 已提交
1207
		}
1208 1209 1210
		if (toggleFullScreen) {
			this.windowService.toggleFullScreen().done(undefined, errors.onUnexpectedError);
		}
I
isidor 已提交
1211 1212
	}

1213 1214 1215 1216 1217 1218 1219 1220 1221 1222
	// 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 已提交
1223
				return; // Cannot resize other parts
1224 1225 1226 1227
		}
	}


1228
	private shouldRestoreLastOpenedViewlet(): boolean {
1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239
		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 已提交
1240
}