workbench.ts 46.7 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 471 472 473 474 475 476 477 478 479 480
	private openUntitledFile() {
		const startupEditor = this.configurationService.lookup('workbench.startupEditor');
		if (!startupEditor.user && !startupEditor.workspace) {
			const welcomeEnabled = this.configurationService.lookup('workbench.welcome.enabled');
			if (welcomeEnabled.value !== undefined && welcomeEnabled.value !== null) {
				return !welcomeEnabled.value;
			}
		}
		return startupEditor.value === 'newUntitledFile';
	}

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

484
		this.toDispose.push(this.lifecycleService.onShutdown(this.shutdownComponents, this));
E
Erich Gamma 已提交
485 486

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

489 490 491
		// Clipboard
		serviceCollection.set(IClipboardService, new ClipboardService());

492 493 494 495 496 497
		// 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);

498 499 500
		// Progress 2
		serviceCollection.set(IProgressService2, new SyncDescriptor(ProgressService2));

501
		// Keybindings
A
Alex Dima 已提交
502
		this.contextKeyService = this.instantiationService.createInstance(ContextKeyService);
503
		serviceCollection.set(IContextKeyService, this.contextKeyService);
504

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

508 509 510
		// List
		serviceCollection.set(IListService, this.instantiationService.createInstance(ListService));

511
		// Context Menu
512
		serviceCollection.set(IContextMenuService, new SyncDescriptor(ContextMenuService));
513

514 515
		// Menus/Actions
		serviceCollection.set(IMenuService, new SyncDescriptor(MenuService));
516

P
Pine Wu 已提交
517
		// Sidebar part
518
		this.sidebarPart = this.instantiationService.createInstance(SidebarPart, Identifiers.SIDEBAR_PART);
E
Erich Gamma 已提交
519 520
		this.toDispose.push(this.sidebarPart);
		this.toShutdown.push(this.sidebarPart);
P
Pine Wu 已提交
521 522 523 524

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

I
isidor 已提交
526
		// Panel service (panel part)
527
		this.panelPart = this.instantiationService.createInstance(PanelPart, Identifiers.PANEL_PART);
I
isidor 已提交
528 529
		this.toDispose.push(this.panelPart);
		this.toShutdown.push(this.panelPart);
530
		serviceCollection.set(IPanelService, this.panelPart);
I
isidor 已提交
531

E
Erich Gamma 已提交
532
		// Activity service (activitybar part)
533
		this.activitybarPart = this.instantiationService.createInstance(ActivitybarPart, Identifiers.ACTIVITYBAR_PART);
E
Erich Gamma 已提交
534 535
		this.toDispose.push(this.activitybarPart);
		this.toShutdown.push(this.activitybarPart);
536
		serviceCollection.set(IActivityBarService, this.activitybarPart);
E
Erich Gamma 已提交
537 538

		// Editor service (editor part)
539
		this.editorPart = this.instantiationService.createInstance(EditorPart, Identifiers.EDITOR_PART, !this.hasFilesToCreateOpenOrDiff);
E
Erich Gamma 已提交
540 541
		this.toDispose.push(this.editorPart);
		this.toShutdown.push(this.editorPart);
542
		this.editorService = this.instantiationService.createInstance(WorkbenchEditorService, this.editorPart);
543
		serviceCollection.set(IWorkbenchEditorService, this.editorService);
544
		serviceCollection.set(IEditorGroupService, this.editorPart);
E
Erich Gamma 已提交
545

546 547 548 549 550 551
		// 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);

552
		// File Service
553 554 555
		const fileService = this.instantiationService.createInstance(FileService);
		serviceCollection.set(IFileService, fileService);
		this.toDispose.push(fileService.onFileChanges(e => this.configurationService.handleWorkspaceFileEvents(e)));
556

557
		// History
558
		serviceCollection.set(IHistoryService, new SyncDescriptor(HistoryService));
559

560
		// Backup File Service
561
		this.backupFileService = this.instantiationService.createInstance(BackupFileService, this.workbenchParams.configuration.backupPath);
562
		serviceCollection.set(IBackupFileService, this.backupFileService);
563

564
		// Text File Service
565
		serviceCollection.set(ITextFileService, new SyncDescriptor(TextFileService));
566

J
Joao Moreno 已提交
567
		// SCM Service
568
		serviceCollection.set(ISCMService, new SyncDescriptor(SCMService));
569

B
Benjamin Pasero 已提交
570
		// Text Model Resolver Service
571
		serviceCollection.set(ITextModelService, new SyncDescriptor(TextModelResolverService));
B
Benjamin Pasero 已提交
572

573
		// Configuration Editing
574 575
		this.configurationEditingService = this.instantiationService.createInstance(ConfigurationEditingService);
		serviceCollection.set(IConfigurationEditingService, this.configurationEditingService);
576

577 578 579
		// Keybinding Editing
		serviceCollection.set(IKeybindingEditingService, this.instantiationService.createInstance(KeybindingsEditingService));

580
		// Configuration Resolver
581
		const workspace = this.contextService.getWorkspace();
582
		serviceCollection.set(IConfigurationResolverService, new SyncDescriptor(ConfigurationResolverService, workspace ? workspace.resource : null, process.env));
583

E
Erich Gamma 已提交
584
		// Quick open service (quick open controller)
585
		this.quickOpen = this.instantiationService.createInstance(QuickOpenController);
E
Erich Gamma 已提交
586 587
		this.toDispose.push(this.quickOpen);
		this.toShutdown.push(this.quickOpen);
588
		serviceCollection.set(IQuickOpenService, this.quickOpen);
E
Erich Gamma 已提交
589

B
polish  
Benjamin Pasero 已提交
590
		// Contributed services
B
Benjamin Pasero 已提交
591
		const contributedServices = getServices();
E
Erich Gamma 已提交
592
		for (let contributedService of contributedServices) {
593
			serviceCollection.set(contributedService.id, contributedService.descriptor);
E
Erich Gamma 已提交
594 595 596
		}

		// Set the some services to registries that have been created eagerly
597 598 599
		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 已提交
600 601 602 603 604
	}

	private initSettings(): void {

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

I
isidor 已提交
607
		// Panel part visibility
608
		const panelRegistry = Registry.as<PanelRegistry>(PanelExtensions.Panels);
B
Benjamin Pasero 已提交
609
		this.panelHidden = this.storageService.getBoolean(Workbench.panelHiddenSettingKey, StorageScope.WORKSPACE, true);
610 611
		if (!panelRegistry.getDefaultPanelId()) {
			this.panelHidden = true; // we hide panel part if there is no default panel
I
isidor 已提交
612
		}
I
isidor 已提交
613

E
Erich Gamma 已提交
614
		// Sidebar position
615 616
		const sideBarPosition = this.configurationService.lookup<string>(Workbench.sidebarPositionConfigurationKey).value;
		this.sideBarPosition = (sideBarPosition === 'right') ? Position.RIGHT : Position.LEFT;
B
Benjamin Pasero 已提交
617 618

		// Statusbar visibility
619 620
		const statusBarVisible = this.configurationService.lookup<string>(Workbench.statusbarVisibleConfigurationKey).value;
		this.statusBarHidden = !statusBarVisible;
S
Sanders Lauture 已提交
621 622 623 624

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

I
isidor 已提交
626 627
		// Zen mode
		this.zenMode = {
I
isidor 已提交
628
			active: false,
629 630 631
			transitionedToFullScreen: false,
			wasSideBarVisible: false,
			wasPanelVisible: false
I
isidor 已提交
632
		};
E
Erich Gamma 已提交
633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653
	}

	/**
	 * 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 已提交
654
		const activeElement = document.activeElement;
E
Erich Gamma 已提交
655 656 657 658
		if (!activeElement) {
			return false;
		}

659 660 661 662 663
		const container = this.getContainer(part);
		return DOM.isAncestor(activeElement, container);
	}

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

	public isVisible(part: Parts): boolean {
B
Benjamin Pasero 已提交
689
		switch (part) {
B
Benjamin Pasero 已提交
690
			case Parts.TITLEBAR_PART:
691
				return this.getCustomTitleBarStyle() && !browser.isFullscreen();
B
Benjamin Pasero 已提交
692
			case Parts.SIDEBAR_PART:
693
				return !this.sideBarHidden;
B
Benjamin Pasero 已提交
694
			case Parts.PANEL_PART:
695
				return !this.panelHidden;
B
Benjamin Pasero 已提交
696
			case Parts.STATUSBAR_PART:
697
				return !this.statusBarHidden;
S
Sanders Lauture 已提交
698
			case Parts.ACTIVITYBAR_PART:
699
				return !this.activityBarHidden;
700
		}
E
Erich Gamma 已提交
701 702 703 704

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

705 706
	public getTitleBarOffset(): number {
		let offset = 0;
707
		if (this.isVisible(Parts.TITLEBAR_PART)) {
708 709 710 711 712 713
			offset = 22 / browser.getZoomFactor(); // adjust the position based on title bar size and zoom factor
		}

		return offset;
	}

714
	private getCustomTitleBarStyle(): 'custom' {
B
Benjamin Pasero 已提交
715
		if (!isMacintosh) {
716
			return null; // custom title bar is only supported on Mac currently
B
Benjamin Pasero 已提交
717 718
		}

719
		const isDev = !this.environmentService.isBuilt || this.environmentService.isExtensionDevelopment;
B
Benjamin Pasero 已提交
720
		if (isDev) {
721
			return null; // not enabled when developing due to https://github.com/electron/electron/issues/3647
B
Benjamin Pasero 已提交
722 723
		}

724
		const windowConfig = this.configurationService.getConfiguration<IWindowSettings>();
725 726 727 728 729
		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 已提交
730

731 732 733 734
			const style = windowConfig.window.titleBarStyle;
			if (style === 'custom') {
				return style;
			}
735 736 737
		}

		return null;
B
Benjamin Pasero 已提交
738 739
	}

740
	private setStatusBarHidden(hidden: boolean, skipLayout?: boolean): void {
741 742
		this.statusBarHidden = hidden;

I
isidor 已提交
743

744 745
		// Layout
		if (!skipLayout) {
746
			this.workbenchLayout.layout();
747 748 749
		}
	}

S
Sanders Lauture 已提交
750 751 752
	public setActivityBarHidden(hidden: boolean, skipLayout?: boolean): void {
		this.activityBarHidden = hidden;

I
isidor 已提交
753

S
Sanders Lauture 已提交
754 755
		// Layout
		if (!skipLayout) {
756
			this.workbenchLayout.layout();
S
Sanders Lauture 已提交
757 758 759
		}
	}

760
	public setSideBarHidden(hidden: boolean, skipLayout?: boolean): TPromise<void> {
E
Erich Gamma 已提交
761 762 763 764 765 766 767 768 769
		this.sideBarHidden = hidden;

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

B
Benjamin Pasero 已提交
770
		// If sidebar becomes hidden, also hide the current active Viewlet if any
B
Benjamin Pasero 已提交
771
		let promise = TPromise.as<any>(null);
E
Erich Gamma 已提交
772
		if (hidden && this.sidebarPart.getActiveViewlet()) {
773 774 775
			promise = this.sidebarPart.hideActiveViewlet().then(() => {
				const activeEditor = this.editorPart.getActiveEditor();
				const activePanel = this.panelPart.getActivePanel();
B
Benjamin Pasero 已提交
776

777 778 779 780 781 782 783
				// 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 已提交
784 785
		}

B
Benjamin Pasero 已提交
786
		// If sidebar becomes visible, show last active Viewlet or default viewlet
E
Erich Gamma 已提交
787
		else if (!hidden && !this.sidebarPart.getActiveViewlet()) {
788
			const viewletToOpen = this.sidebarPart.getLastActiveViewletId();
E
Erich Gamma 已提交
789
			if (viewletToOpen) {
790
				promise = this.sidebarPart.openViewlet(viewletToOpen, true);
E
Erich Gamma 已提交
791 792 793
			}
		}

794
		return promise.then(() => {
795

796
			// Remember in settings
797 798 799 800 801 802
			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);
			}
803 804 805

			// Layout
			if (!skipLayout) {
806
				this.workbenchLayout.layout();
807 808
			}
		});
E
Erich Gamma 已提交
809 810
	}

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

814 815 816 817 818 819 820
		// Adjust CSS
		if (hidden) {
			this.workbench.addClass('nopanel');
		} else {
			this.workbench.removeClass('nopanel');
		}

I
isidor 已提交
821
		// If panel part becomes hidden, also hide the current active panel if any
822
		let promise = TPromise.as<any>(null);
I
isidor 已提交
823
		if (hidden && this.panelPart.getActivePanel()) {
824 825 826 827 828 829 830
			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 已提交
831 832 833 834
		}

		// If panel part becomes visible, show last active panel or default panel
		else if (!hidden && !this.panelPart.getActivePanel()) {
835
			const panelToOpen = this.panelPart.getLastActivePanelId();
I
isidor 已提交
836
			if (panelToOpen) {
837
				promise = this.panelPart.openPanel(panelToOpen, true);
I
isidor 已提交
838 839 840
			}
		}

841
		return promise.then(() => {
842

843
			// Remember in settings
844 845 846 847 848
			if (!hidden) {
				this.storageService.store(Workbench.panelHiddenSettingKey, 'false', StorageScope.WORKSPACE);
			} else {
				this.storageService.remove(Workbench.panelHiddenSettingKey, StorageScope.WORKSPACE);
			}
849 850 851

			// Layout
			if (!skipLayout) {
852
				this.workbenchLayout.layout();
853 854
			}
		});
I
isidor 已提交
855 856
	}

I
isidor 已提交
857
	public toggleMaximizedPanel(): void {
858
		this.workbenchLayout.layout({ toggleMaximizedPanel: true });
I
isidor 已提交
859 860
	}

I
isidor 已提交
861 862 863 864
	public isPanelMaximized(): boolean {
		return this.workbenchLayout.isPanelMaximized();
	}

E
Erich Gamma 已提交
865 866 867 868
	public getSideBarPosition(): Position {
		return this.sideBarPosition;
	}

869
	private setSideBarPosition(position: Position): void {
E
Erich Gamma 已提交
870
		if (this.sideBarHidden) {
871
			this.setSideBarHidden(false, true /* Skip Layout */).done(undefined, errors.onUnexpectedError);
E
Erich Gamma 已提交
872 873
		}

B
Benjamin Pasero 已提交
874 875
		const newPositionValue = (position === Position.LEFT) ? 'left' : 'right';
		const oldPositionValue = (this.sideBarPosition === Position.LEFT) ? 'left' : 'right';
E
Erich Gamma 已提交
876 877 878 879 880 881 882 883
		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);

884 885 886 887
		// Update Styles
		this.activitybarPart.updateStyles();
		this.sidebarPart.updateStyles();

E
Erich Gamma 已提交
888
		// Layout
889
		this.workbenchLayout.layout();
E
Erich Gamma 已提交
890 891
	}

B
Benjamin Pasero 已提交
892
	public dispose(): void {
E
Erich Gamma 已提交
893
		if (this.isStarted()) {
B
Benjamin Pasero 已提交
894
			this.shutdownComponents();
E
Erich Gamma 已提交
895 896 897
			this.workbenchShutdown = true;
		}

J
Joao Moreno 已提交
898
		this.toDispose = dispose(this.toDispose);
E
Erich Gamma 已提交
899 900 901 902 903 904
	}

	/**
	 * 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 已提交
905
	public layout(options?: ILayoutOptions): void {
E
Erich Gamma 已提交
906
		if (this.isStarted()) {
B
Benjamin Pasero 已提交
907
			this.workbenchLayout.layout(options);
E
Erich Gamma 已提交
908 909 910
		}
	}

911 912 913 914 915 916
	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 已提交
917

I
isidor 已提交
918
		// Preserve zen mode only on reload. Real quit gets out of zen mode so novice users do not get stuck in zen mode.
919 920 921 922 923 924 925
		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 已提交
926 927 928 929 930 931 932 933

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

	private registerListeners(): void {

		// Listen to editor changes
934
		this.toDispose.push(this.editorPart.onEditorsChanged(() => this.onEditorsChanged()));
935 936

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

940 941 942 943 944
		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()));
945 946 947 948 949 950 951 952 953 954

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

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

955
		// Apply as CSS class
956 957 958 959 960
		const isFullscreen = browser.isFullscreen();
		if (isFullscreen) {
			this.addClass('fullscreen');
		} else {
			this.removeClass('fullscreen');
I
isidor 已提交
961 962
			if (this.zenMode.transitionedToFullScreen && this.zenMode.active) {
				this.toggleZenMode();
I
isidor 已提交
963
			}
964
		}
965

966 967 968 969 970
		// 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
971
		}
E
Erich Gamma 已提交
972 973
	}

974
	private onEditorsChanged(): void {
B
Benjamin Pasero 已提交
975
		const visibleEditors = this.editorService.getVisibleEditors().length;
E
Erich Gamma 已提交
976 977 978 979

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

980
		const editorContainer = this.editorPart.getContainer();
E
Erich Gamma 已提交
981
		if (visibleEditors === 0) {
982
			this.editorsVisibleContext.reset();
983
			this.editorBackgroundDelayer.trigger(() => editorContainer.addClass('empty'));
E
Erich Gamma 已提交
984
		} else {
985
			this.editorsVisibleContext.set(true);
986
			this.editorBackgroundDelayer.trigger(() => editorContainer.removeClass('empty'));
E
Erich Gamma 已提交
987 988 989
		}
	}

990
	private onDidUpdateConfiguration(skipLayout?: boolean): void {
991
		const newSidebarPositionValue = this.configurationService.lookup<string>(Workbench.sidebarPositionConfigurationKey).value;
992
		const newSidebarPosition = (newSidebarPositionValue === 'right') ? Position.RIGHT : Position.LEFT;
993 994 995
		if (newSidebarPosition !== this.getSideBarPosition()) {
			this.setSideBarPosition(newSidebarPosition);
		}
996

997 998 999 1000 1001
		if (!this.zenMode.active) {
			const newStatusbarHiddenValue = !this.configurationService.lookup<boolean>(Workbench.statusbarVisibleConfigurationKey).value;
			if (newStatusbarHiddenValue !== this.statusBarHidden) {
				this.setStatusBarHidden(newStatusbarHiddenValue, skipLayout);
			}
S
Sanders Lauture 已提交
1002

1003 1004 1005 1006
			const newActivityBarHiddenValue = !this.configurationService.lookup<boolean>(Workbench.activityBarVisibleConfigurationKey).value;
			if (newActivityBarHiddenValue !== this.activityBarHidden) {
				this.setActivityBarHidden(newActivityBarHiddenValue, skipLayout);
			}
S
Sanders Lauture 已提交
1007
		}
1008 1009
	}

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

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

	private createWorkbench(): void {

		// Create Workbench DIV Off-DOM
		this.workbenchContainer = $('.monaco-workbench-container');
1032
		this.workbench = $().div({ 'class': 'monaco-workbench ' + (isWindows ? 'windows' : isLinux ? 'linux' : 'mac'), id: Identifiers.WORKBENCH_CONTAINER }).appendTo(this.workbenchContainer);
E
Erich Gamma 已提交
1033 1034 1035 1036 1037 1038 1039 1040
	}

	private renderWorkbench(): void {

		// Apply sidebar state as CSS class
		if (this.sideBarHidden) {
			this.workbench.addClass('nosidebar');
		}
1041 1042 1043
		if (this.panelHidden) {
			this.workbench.addClass('nopanel');
		}
E
Erich Gamma 已提交
1044

B
Benjamin Pasero 已提交
1045
		// Apply title style if shown
1046 1047 1048 1049 1050 1051 1052 1053
		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 已提交
1054 1055
		}

E
Erich Gamma 已提交
1056
		// Create Parts
B
Benjamin Pasero 已提交
1057
		this.createTitlebarPart();
E
Erich Gamma 已提交
1058 1059 1060
		this.createActivityBarPart();
		this.createSidebarPart();
		this.createEditorPart();
1061
		this.createPanelPart();
E
Erich Gamma 已提交
1062 1063 1064 1065 1066 1067
		this.createStatusbarPart();

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

B
Benjamin Pasero 已提交
1068 1069 1070 1071 1072 1073 1074 1075 1076 1077
	private createTitlebarPart(): void {
		const titlebarContainer = $(this.workbench).div({
			'class': ['part', 'titlebar'],
			id: Identifiers.TITLEBAR_PART,
			role: 'contentinfo'
		});

		this.titlebarPart.create(titlebarContainer);
	}

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

		this.activitybarPart.create(activitybarPartContainer);
	}

	private createSidebarPart(): void {
B
Benjamin Pasero 已提交
1090
		const sidebarPartContainer = $(this.workbench)
E
Erich Gamma 已提交
1091 1092
			.div({
				'class': ['part', 'sidebar', this.sideBarPosition === Position.LEFT ? 'left' : 'right'],
1093 1094
				id: Identifiers.SIDEBAR_PART,
				role: 'complementary'
E
Erich Gamma 已提交
1095 1096 1097 1098 1099
			});

		this.sidebarPart.create(sidebarPartContainer);
	}

I
isidor 已提交
1100
	private createPanelPart(): void {
B
Benjamin Pasero 已提交
1101
		const panelPartContainer = $(this.workbench)
I
isidor 已提交
1102
			.div({
1103
				'class': ['part', 'panel'],
1104 1105
				id: Identifiers.PANEL_PART,
				role: 'complementary'
I
isidor 已提交
1106 1107 1108 1109 1110
			});

		this.panelPart.create(panelPartContainer);
	}

E
Erich Gamma 已提交
1111
	private createEditorPart(): void {
B
Benjamin Pasero 已提交
1112
		const editorContainer = $(this.workbench)
E
Erich Gamma 已提交
1113
			.div({
1114
				'class': ['part', 'editor', 'empty'],
1115 1116
				id: Identifiers.EDITOR_PART,
				role: 'main'
E
Erich Gamma 已提交
1117 1118 1119 1120 1121 1122
			});

		this.editorPart.create(editorContainer);
	}

	private createStatusbarPart(): void {
B
Benjamin Pasero 已提交
1123
		const statusbarContainer = $(this.workbench).div({
E
Erich Gamma 已提交
1124
			'class': ['part', 'statusbar'],
1125 1126
			id: Identifiers.STATUSBAR_PART,
			role: 'contentinfo'
E
Erich Gamma 已提交
1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143
		});

		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 已提交
1144 1145 1146 1147 1148 1149
	public getPanelPart(): PanelPart {
		assert.ok(this.workbenchStarted, 'Workbench is not started. Call startup() first.');

		return this.panelPart;
	}

E
Erich Gamma 已提交
1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166
	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);
		}
	}
1167 1168 1169 1170

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

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

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

I
isidor 已提交
1212
		if (!skipLayout) {
1213
			this.layout();
I
isidor 已提交
1214
		}
1215 1216 1217
		if (toggleFullScreen) {
			this.windowService.toggleFullScreen().done(undefined, errors.onUnexpectedError);
		}
I
isidor 已提交
1218 1219
	}

1220 1221 1222 1223 1224 1225 1226 1227 1228 1229
	// 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 已提交
1230
				return; // Cannot resize other parts
1231 1232 1233 1234
		}
	}


1235
	private shouldRestoreLastOpenedViewlet(): boolean {
1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246
		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 已提交
1247
}