workbench.ts 49.9 KB
Newer Older
E
Erich Gamma 已提交
1 2 3 4 5 6 7 8
/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/

'use strict';

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

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

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

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

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

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

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

137 138
const Identifiers = {
	WORKBENCH_CONTAINER: 'workbench.main.container',
B
Benjamin Pasero 已提交
139
	TITLEBAR_PART: 'workbench.parts.titlebar',
140 141 142 143 144 145 146
	ACTIVITYBAR_PART: 'workbench.parts.activitybar',
	SIDEBAR_PART: 'workbench.parts.sidebar',
	PANEL_PART: 'workbench.parts.panel',
	EDITOR_PART: 'workbench.parts.editor',
	STATUSBAR_PART: 'workbench.parts.statusbar'
};

E
Erich Gamma 已提交
147
/**
B
Benjamin Pasero 已提交
148
 * The workbench creates and lays out all parts that make up the workbench.
E
Erich Gamma 已提交
149 150 151 152
 */
export class Workbench implements IPartService {

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

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

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

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

165 166
	private _onTitleBarVisibilityChange: Emitter<void>;

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

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

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

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

238
		this.hasFilesToCreateOpenOrDiff =
B
Benjamin Pasero 已提交
239 240 241
			(configuration.filesToCreate && configuration.filesToCreate.length > 0) ||
			(configuration.filesToOpen && configuration.filesToOpen.length > 0) ||
			(configuration.filesToDiff && configuration.filesToDiff.length > 0);
242

E
Erich Gamma 已提交
243 244
		this.toDispose = [];
		this.toShutdown = [];
245

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

249 250
		this._onTitleBarVisibilityChange = new Emitter<void>();

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

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

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

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

281 282 283
			// Install some global actions
			this.createGlobalActions();

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

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

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

			// Settings
			this.initSettings();

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

			// Workbench Layout
			this.createWorkbenchLayout();

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

			// Rethrow
			throw error;
		}
	}

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

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

		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 }
		});
432 433
	}

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

		// Files to open, diff or create
437
		if (this.hasFilesToCreateOpenOrDiff) {
B
Benjamin Pasero 已提交
438 439 440
			const filesToCreate = this.toInputs(this.workbenchParams.configuration.filesToCreate);
			const filesToOpen = this.toInputs(this.workbenchParams.configuration.filesToOpen);
			const filesToDiff = this.toInputs(this.workbenchParams.configuration.filesToDiff);
B
Benjamin Pasero 已提交
441 442

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

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

460
				return TPromise.as([].concat(filesToOpen).concat(filesToCreateInputs));
B
Benjamin Pasero 已提交
461 462 463
			}
		}

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

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

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

		return TPromise.as([]);
	}

B
Benjamin Pasero 已提交
482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505
	private toInputs(paths?: IPath[]): IResourceInput[] {
		if (!paths || !paths.length) {
			return [];
		}

		return paths.map(p => {
			const input = <IResourceInput>{};
			input.resource = URI.file(p.filePath);

			input.options = {
				pinned: true // opening on startup is always pinned and not preview
			};

			if (p.lineNumber) {
				input.options.selection = {
					startLineNumber: p.lineNumber,
					startColumn: p.columnNumber
				};
			}

			return input;
		});
	}

506
	private openUntitledFile() {
507
		const startupEditor = this.configurationService.lookup('workbench.startupEditor');
B
Benjamin Pasero 已提交
508 509

		// Fallback to previous workbench.welcome.enabled setting in case startupEditor is not defined
510 511
		if (!startupEditor.user && !startupEditor.workspace) {
			const welcomeEnabled = this.configurationService.lookup('workbench.welcome.enabled');
B
Benjamin Pasero 已提交
512
			if (typeof welcomeEnabled.value === 'boolean') {
513 514 515
				return !welcomeEnabled.value;
			}
		}
B
Benjamin Pasero 已提交
516

517
		return startupEditor.value === 'newUntitledFile';
518 519
	}

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

523
		this.toDispose.push(this.lifecycleService.onShutdown(this.shutdownComponents, this));
E
Erich Gamma 已提交
524 525

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

528 529 530
		// Clipboard
		serviceCollection.set(IClipboardService, new ClipboardService());

531 532 533 534 535 536
		// 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);

537 538 539
		// Progress 2
		serviceCollection.set(IProgressService2, new SyncDescriptor(ProgressService2));

540
		// Keybindings
A
Alex Dima 已提交
541
		this.contextKeyService = this.instantiationService.createInstance(ContextKeyService);
542
		serviceCollection.set(IContextKeyService, this.contextKeyService);
543

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

547 548 549
		// List
		serviceCollection.set(IListService, this.instantiationService.createInstance(ListService));

550
		// Context Menu
551
		serviceCollection.set(IContextMenuService, new SyncDescriptor(ContextMenuService));
552

553 554
		// Menus/Actions
		serviceCollection.set(IMenuService, new SyncDescriptor(MenuService));
555

P
Pine Wu 已提交
556
		// Sidebar part
557
		this.sidebarPart = this.instantiationService.createInstance(SidebarPart, Identifiers.SIDEBAR_PART);
E
Erich Gamma 已提交
558 559
		this.toDispose.push(this.sidebarPart);
		this.toShutdown.push(this.sidebarPart);
P
Pine Wu 已提交
560 561 562 563

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

I
isidor 已提交
565
		// Panel service (panel part)
566
		this.panelPart = this.instantiationService.createInstance(PanelPart, Identifiers.PANEL_PART);
I
isidor 已提交
567 568
		this.toDispose.push(this.panelPart);
		this.toShutdown.push(this.panelPart);
569
		serviceCollection.set(IPanelService, this.panelPart);
I
isidor 已提交
570

E
Erich Gamma 已提交
571
		// Activity service (activitybar part)
572
		this.activitybarPart = this.instantiationService.createInstance(ActivitybarPart, Identifiers.ACTIVITYBAR_PART);
E
Erich Gamma 已提交
573 574
		this.toDispose.push(this.activitybarPart);
		this.toShutdown.push(this.activitybarPart);
575
		serviceCollection.set(IActivityBarService, this.activitybarPart);
E
Erich Gamma 已提交
576 577

		// Editor service (editor part)
578
		this.editorPart = this.instantiationService.createInstance(EditorPart, Identifiers.EDITOR_PART, !this.hasFilesToCreateOpenOrDiff);
E
Erich Gamma 已提交
579 580
		this.toDispose.push(this.editorPart);
		this.toShutdown.push(this.editorPart);
581
		this.editorService = this.instantiationService.createInstance(WorkbenchEditorService, this.editorPart);
582
		serviceCollection.set(IWorkbenchEditorService, this.editorService);
583
		serviceCollection.set(IEditorGroupService, this.editorPart);
E
Erich Gamma 已提交
584

585 586 587 588 589 590
		// 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);

591
		// File Service
592
		const fileService = this.instantiationService.createInstance(RemoteFileService);
593 594
		serviceCollection.set(IFileService, fileService);
		this.toDispose.push(fileService.onFileChanges(e => this.configurationService.handleWorkspaceFileEvents(e)));
595

596
		// History
597
		serviceCollection.set(IHistoryService, new SyncDescriptor(HistoryService));
598

599
		// Backup File Service
600
		this.backupFileService = this.instantiationService.createInstance(BackupFileService, this.workbenchParams.configuration.backupPath);
601
		serviceCollection.set(IBackupFileService, this.backupFileService);
602

603
		// Text File Service
604
		serviceCollection.set(ITextFileService, new SyncDescriptor(TextFileService));
605

J
Joao Moreno 已提交
606
		// SCM Service
607
		serviceCollection.set(ISCMService, new SyncDescriptor(SCMService));
608

B
Benjamin Pasero 已提交
609
		// Text Model Resolver Service
610
		serviceCollection.set(ITextModelService, new SyncDescriptor(TextModelResolverService));
B
Benjamin Pasero 已提交
611

612 613 614 615
		// JSON Editing
		const jsonEditingService = this.instantiationService.createInstance(JSONEditingService);
		serviceCollection.set(IJSONEditingService, jsonEditingService);

616
		// Configuration Editing
617 618
		this.configurationEditingService = this.instantiationService.createInstance(ConfigurationEditingService);
		serviceCollection.set(IConfigurationEditingService, this.configurationEditingService);
619

620 621 622
		// Workspace Editing
		serviceCollection.set(IWorkspaceEditingService, new SyncDescriptor(WorkspaceEditingService));

623 624 625
		// Keybinding Editing
		serviceCollection.set(IKeybindingEditingService, this.instantiationService.createInstance(KeybindingsEditingService));

626
		// Configuration Resolver
B
Benjamin Pasero 已提交
627
		serviceCollection.set(IConfigurationResolverService, new SyncDescriptor(ConfigurationResolverService, process.env));
628

E
Erich Gamma 已提交
629
		// Quick open service (quick open controller)
630
		this.quickOpen = this.instantiationService.createInstance(QuickOpenController);
E
Erich Gamma 已提交
631 632
		this.toDispose.push(this.quickOpen);
		this.toShutdown.push(this.quickOpen);
633
		serviceCollection.set(IQuickOpenService, this.quickOpen);
E
Erich Gamma 已提交
634

B
polish  
Benjamin Pasero 已提交
635
		// Contributed services
B
Benjamin Pasero 已提交
636
		const contributedServices = getServices();
E
Erich Gamma 已提交
637
		for (let contributedService of contributedServices) {
638
			serviceCollection.set(contributedService.id, contributedService.descriptor);
E
Erich Gamma 已提交
639 640 641
		}

		// Set the some services to registries that have been created eagerly
642 643 644
		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 已提交
645 646 647 648 649
	}

	private initSettings(): void {

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

I
isidor 已提交
652
		// Panel part visibility
653
		const panelRegistry = Registry.as<PanelRegistry>(PanelExtensions.Panels);
B
Benjamin Pasero 已提交
654
		this.panelHidden = this.storageService.getBoolean(Workbench.panelHiddenSettingKey, StorageScope.WORKSPACE, true);
655 656
		if (!panelRegistry.getDefaultPanelId()) {
			this.panelHidden = true; // we hide panel part if there is no default panel
I
isidor 已提交
657
		}
I
isidor 已提交
658

E
Erich Gamma 已提交
659
		// Sidebar position
660 661
		const sideBarPosition = this.configurationService.lookup<string>(Workbench.sidebarPositionConfigurationKey).value;
		this.sideBarPosition = (sideBarPosition === 'right') ? Position.RIGHT : Position.LEFT;
B
Benjamin Pasero 已提交
662 663

		// Statusbar visibility
664 665
		const statusBarVisible = this.configurationService.lookup<string>(Workbench.statusbarVisibleConfigurationKey).value;
		this.statusBarHidden = !statusBarVisible;
S
Sanders Lauture 已提交
666 667 668 669

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

671 672 673
		// Font aliasing
		this.fontAliasing = this.configurationService.lookup<string>(Workbench.fontAliasingConfigurationKey).value;

I
isidor 已提交
674 675
		// Zen mode
		this.zenMode = {
I
isidor 已提交
676
			active: false,
677 678 679
			transitionedToFullScreen: false,
			wasSideBarVisible: false,
			wasPanelVisible: false
I
isidor 已提交
680
		};
E
Erich Gamma 已提交
681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701
	}

	/**
	 * 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 已提交
702
		const activeElement = document.activeElement;
E
Erich Gamma 已提交
703 704 705 706
		if (!activeElement) {
			return false;
		}

707 708 709 710 711
		const container = this.getContainer(part);
		return DOM.isAncestor(activeElement, container);
	}

	public getContainer(part: Parts): HTMLElement {
E
Erich Gamma 已提交
712 713
		let container: Builder = null;
		switch (part) {
B
Benjamin Pasero 已提交
714 715 716
			case Parts.TITLEBAR_PART:
				container = this.titlebarPart.getContainer();
				break;
E
Erich Gamma 已提交
717 718 719 720 721 722
			case Parts.ACTIVITYBAR_PART:
				container = this.activitybarPart.getContainer();
				break;
			case Parts.SIDEBAR_PART:
				container = this.sidebarPart.getContainer();
				break;
I
isidor 已提交
723 724 725
			case Parts.PANEL_PART:
				container = this.panelPart.getContainer();
				break;
E
Erich Gamma 已提交
726 727 728 729 730 731 732
			case Parts.EDITOR_PART:
				container = this.editorPart.getContainer();
				break;
			case Parts.STATUSBAR_PART:
				container = this.statusbarPart.getContainer();
				break;
		}
733
		return container && container.getHTMLElement();
E
Erich Gamma 已提交
734 735 736
	}

	public isVisible(part: Parts): boolean {
B
Benjamin Pasero 已提交
737
		switch (part) {
B
Benjamin Pasero 已提交
738
			case Parts.TITLEBAR_PART:
739
				return this.getCustomTitleBarStyle() && !browser.isFullscreen();
B
Benjamin Pasero 已提交
740
			case Parts.SIDEBAR_PART:
741
				return !this.sideBarHidden;
B
Benjamin Pasero 已提交
742
			case Parts.PANEL_PART:
743
				return !this.panelHidden;
B
Benjamin Pasero 已提交
744
			case Parts.STATUSBAR_PART:
745
				return !this.statusBarHidden;
S
Sanders Lauture 已提交
746
			case Parts.ACTIVITYBAR_PART:
747
				return !this.activityBarHidden;
748
		}
E
Erich Gamma 已提交
749 750 751 752

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

753 754
	public getTitleBarOffset(): number {
		let offset = 0;
755
		if (this.isVisible(Parts.TITLEBAR_PART)) {
756 757 758 759 760 761
			offset = 22 / browser.getZoomFactor(); // adjust the position based on title bar size and zoom factor
		}

		return offset;
	}

762
	private getCustomTitleBarStyle(): 'custom' {
B
Benjamin Pasero 已提交
763
		if (!isMacintosh) {
764
			return null; // custom title bar is only supported on Mac currently
B
Benjamin Pasero 已提交
765 766
		}

767
		const isDev = !this.environmentService.isBuilt || this.environmentService.isExtensionDevelopment;
B
Benjamin Pasero 已提交
768
		if (isDev) {
769
			return null; // not enabled when developing due to https://github.com/electron/electron/issues/3647
B
Benjamin Pasero 已提交
770 771
		}

772
		const windowConfig = this.configurationService.getConfiguration<IWindowSettings>();
773 774 775 776 777
		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 已提交
778

779 780 781 782
			const style = windowConfig.window.titleBarStyle;
			if (style === 'custom') {
				return style;
			}
783 784 785
		}

		return null;
B
Benjamin Pasero 已提交
786 787
	}

788
	private setStatusBarHidden(hidden: boolean, skipLayout?: boolean): void {
789 790
		this.statusBarHidden = hidden;

I
isidor 已提交
791

792 793
		// Layout
		if (!skipLayout) {
794
			this.workbenchLayout.layout();
795 796 797
		}
	}

S
Sanders Lauture 已提交
798 799 800
	public setActivityBarHidden(hidden: boolean, skipLayout?: boolean): void {
		this.activityBarHidden = hidden;

I
isidor 已提交
801

S
Sanders Lauture 已提交
802 803
		// Layout
		if (!skipLayout) {
804
			this.workbenchLayout.layout();
S
Sanders Lauture 已提交
805 806 807
		}
	}

808
	public setSideBarHidden(hidden: boolean, skipLayout?: boolean): TPromise<void> {
E
Erich Gamma 已提交
809 810 811 812 813 814 815 816 817
		this.sideBarHidden = hidden;

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

B
Benjamin Pasero 已提交
818
		// If sidebar becomes hidden, also hide the current active Viewlet if any
B
Benjamin Pasero 已提交
819
		let promise = TPromise.as<any>(null);
E
Erich Gamma 已提交
820
		if (hidden && this.sidebarPart.getActiveViewlet()) {
821 822 823
			promise = this.sidebarPart.hideActiveViewlet().then(() => {
				const activeEditor = this.editorPart.getActiveEditor();
				const activePanel = this.panelPart.getActivePanel();
B
Benjamin Pasero 已提交
824

825 826 827 828 829 830 831
				// 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 已提交
832 833
		}

B
Benjamin Pasero 已提交
834
		// If sidebar becomes visible, show last active Viewlet or default viewlet
E
Erich Gamma 已提交
835
		else if (!hidden && !this.sidebarPart.getActiveViewlet()) {
836
			const viewletToOpen = this.sidebarPart.getLastActiveViewletId();
E
Erich Gamma 已提交
837
			if (viewletToOpen) {
838
				promise = this.sidebarPart.openViewlet(viewletToOpen, true);
E
Erich Gamma 已提交
839 840 841
			}
		}

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

844
			// Remember in settings
845 846 847 848 849 850
			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);
			}
851 852 853

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

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

862 863 864 865 866 867 868
		// Adjust CSS
		if (hidden) {
			this.workbench.addClass('nopanel');
		} else {
			this.workbench.removeClass('nopanel');
		}

I
isidor 已提交
869
		// If panel part becomes hidden, also hide the current active panel if any
870
		let promise = TPromise.as<any>(null);
I
isidor 已提交
871
		if (hidden && this.panelPart.getActivePanel()) {
872 873 874 875 876 877 878
			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 已提交
879 880 881 882
		}

		// If panel part becomes visible, show last active panel or default panel
		else if (!hidden && !this.panelPart.getActivePanel()) {
883
			const panelToOpen = this.panelPart.getLastActivePanelId();
I
isidor 已提交
884
			if (panelToOpen) {
885
				promise = this.panelPart.openPanel(panelToOpen, true);
I
isidor 已提交
886 887 888
			}
		}

889
		return promise.then(() => {
890

891
			// Remember in settings
892 893 894 895 896
			if (!hidden) {
				this.storageService.store(Workbench.panelHiddenSettingKey, 'false', StorageScope.WORKSPACE);
			} else {
				this.storageService.remove(Workbench.panelHiddenSettingKey, StorageScope.WORKSPACE);
			}
897 898 899

			// Layout
			if (!skipLayout) {
900
				this.workbenchLayout.layout();
901 902
			}
		});
I
isidor 已提交
903 904
	}

I
isidor 已提交
905
	public toggleMaximizedPanel(): void {
906
		this.workbenchLayout.layout({ toggleMaximizedPanel: true });
I
isidor 已提交
907 908
	}

I
isidor 已提交
909 910 911 912
	public isPanelMaximized(): boolean {
		return this.workbenchLayout.isPanelMaximized();
	}

E
Erich Gamma 已提交
913 914 915 916
	public getSideBarPosition(): Position {
		return this.sideBarPosition;
	}

917
	private setSideBarPosition(position: Position): void {
E
Erich Gamma 已提交
918
		if (this.sideBarHidden) {
919
			this.setSideBarHidden(false, true /* Skip Layout */).done(undefined, errors.onUnexpectedError);
E
Erich Gamma 已提交
920 921
		}

B
Benjamin Pasero 已提交
922 923
		const newPositionValue = (position === Position.LEFT) ? 'left' : 'right';
		const oldPositionValue = (this.sideBarPosition === Position.LEFT) ? 'left' : 'right';
E
Erich Gamma 已提交
924 925 926 927 928 929 930 931
		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);

932 933 934 935
		// Update Styles
		this.activitybarPart.updateStyles();
		this.sidebarPart.updateStyles();

E
Erich Gamma 已提交
936
		// Layout
937
		this.workbenchLayout.layout();
E
Erich Gamma 已提交
938 939
	}

940 941
	private setFontAliasing(aliasing: string) {
		this.fontAliasing = aliasing;
B
Benjamin Pasero 已提交
942

943 944 945
		document.body.style['-webkit-font-smoothing'] = (aliasing === 'default' ? '' : aliasing);
	}

B
Benjamin Pasero 已提交
946
	public dispose(): void {
E
Erich Gamma 已提交
947
		if (this.isStarted()) {
B
Benjamin Pasero 已提交
948
			this.shutdownComponents();
E
Erich Gamma 已提交
949 950 951
			this.workbenchShutdown = true;
		}

J
Joao Moreno 已提交
952
		this.toDispose = dispose(this.toDispose);
E
Erich Gamma 已提交
953 954 955 956 957 958
	}

	/**
	 * 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 已提交
959
	public layout(options?: ILayoutOptions): void {
E
Erich Gamma 已提交
960
		if (this.isStarted()) {
B
Benjamin Pasero 已提交
961
			this.workbenchLayout.layout(options);
E
Erich Gamma 已提交
962 963 964
		}
	}

965 966 967 968 969 970
	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 已提交
971

I
isidor 已提交
972
		// Preserve zen mode only on reload. Real quit gets out of zen mode so novice users do not get stuck in zen mode.
973 974 975 976 977 978 979
		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 已提交
980 981 982 983 984 985 986 987

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

	private registerListeners(): void {

		// Listen to editor changes
988
		this.toDispose.push(this.editorPart.onEditorsChanged(() => this.onEditorsChanged()));
989 990

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

994 995 996 997 998
		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()));
999 1000 1001 1002 1003 1004 1005 1006 1007 1008

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

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

1009
		// Apply as CSS class
1010 1011 1012 1013 1014
		const isFullscreen = browser.isFullscreen();
		if (isFullscreen) {
			this.addClass('fullscreen');
		} else {
			this.removeClass('fullscreen');
I
isidor 已提交
1015 1016
			if (this.zenMode.transitionedToFullScreen && this.zenMode.active) {
				this.toggleZenMode();
I
isidor 已提交
1017
			}
1018
		}
1019

1020 1021 1022 1023 1024
		// 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
1025
		}
E
Erich Gamma 已提交
1026 1027
	}

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

1031 1032
		// Close when empty: check if we should close the window based on the setting
		// Overruled by: window has a workspace opened or this window is for extension development
1033
		// or setting is disabled. Also enabled when running with --wait from the command line.
1034 1035
		if (visibleEditors === 0 && !this.contextService.hasWorkspace() && !this.environmentService.isExtensionDevelopment) {
			const closeWhenEmpty = this.configurationService.lookup<boolean>(Workbench.closeWhenEmptyConfigurationKey).value;
1036
			if (closeWhenEmpty || this.environmentService.args.wait) {
1037 1038 1039 1040
				this.closeEmptyWindowScheduler.schedule();
			}
		}

E
Erich Gamma 已提交
1041 1042
		// We update the editorpart class to indicate if an editor is opened or not
		// through a delay to accomodate for fast editor switching
B
Benjamin Pasero 已提交
1043 1044 1045 1046 1047 1048
		this.handleEditorBackground();
	}

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

1049
		const editorContainer = this.editorPart.getContainer();
E
Erich Gamma 已提交
1050
		if (visibleEditors === 0) {
1051
			this.editorsVisibleContext.reset();
1052
			this.editorBackgroundDelayer.trigger(() => editorContainer.addClass('empty'));
E
Erich Gamma 已提交
1053
		} else {
1054
			this.editorsVisibleContext.set(true);
1055
			this.editorBackgroundDelayer.trigger(() => editorContainer.removeClass('empty'));
E
Erich Gamma 已提交
1056 1057 1058
		}
	}

1059 1060 1061 1062 1063 1064 1065
	private onAllEditorsClosed(): void {
		const visibleEditors = this.editorService.getVisibleEditors().length;
		if (visibleEditors === 0) {
			this.windowService.closeWindow();
		}
	}

1066
	private onDidUpdateConfiguration(skipLayout?: boolean): void {
1067
		const newSidebarPositionValue = this.configurationService.lookup<string>(Workbench.sidebarPositionConfigurationKey).value;
1068
		const newSidebarPosition = (newSidebarPositionValue === 'right') ? Position.RIGHT : Position.LEFT;
1069 1070 1071
		if (newSidebarPosition !== this.getSideBarPosition()) {
			this.setSideBarPosition(newSidebarPosition);
		}
1072

1073 1074 1075 1076 1077
		const fontAliasing = this.configurationService.lookup<string>(Workbench.fontAliasingConfigurationKey).value;
		if (fontAliasing !== this.fontAliasing) {
			this.setFontAliasing(fontAliasing);
		}

1078 1079 1080 1081 1082
		if (!this.zenMode.active) {
			const newStatusbarHiddenValue = !this.configurationService.lookup<boolean>(Workbench.statusbarVisibleConfigurationKey).value;
			if (newStatusbarHiddenValue !== this.statusBarHidden) {
				this.setStatusBarHidden(newStatusbarHiddenValue, skipLayout);
			}
S
Sanders Lauture 已提交
1083

1084 1085 1086 1087
			const newActivityBarHiddenValue = !this.configurationService.lookup<boolean>(Workbench.activityBarVisibleConfigurationKey).value;
			if (newActivityBarHiddenValue !== this.activityBarHidden) {
				this.setActivityBarHidden(newActivityBarHiddenValue, skipLayout);
			}
S
Sanders Lauture 已提交
1088
		}
1089 1090
	}

E
Erich Gamma 已提交
1091 1092 1093 1094
	private createWorkbenchLayout(): void {
		this.workbenchLayout = this.instantiationService.createInstance(WorkbenchLayout,
			$(this.container),							// Parent
			this.workbench,								// Workbench Container
I
isidor 已提交
1095
			{
B
Benjamin Pasero 已提交
1096
				titlebar: this.titlebarPart,			// Title Bar
I
isidor 已提交
1097 1098 1099 1100 1101 1102
				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 已提交
1103
			this.quickOpen								// Quickopen
E
Erich Gamma 已提交
1104 1105 1106 1107 1108 1109 1110 1111 1112
		);

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

	private createWorkbench(): void {

		// Create Workbench DIV Off-DOM
		this.workbenchContainer = $('.monaco-workbench-container');
1113
		this.workbench = $().div({ 'class': 'monaco-workbench ' + (isWindows ? 'windows' : isLinux ? 'linux' : 'mac'), id: Identifiers.WORKBENCH_CONTAINER }).appendTo(this.workbenchContainer);
E
Erich Gamma 已提交
1114 1115 1116 1117 1118 1119 1120 1121
	}

	private renderWorkbench(): void {

		// Apply sidebar state as CSS class
		if (this.sideBarHidden) {
			this.workbench.addClass('nosidebar');
		}
1122 1123 1124
		if (this.panelHidden) {
			this.workbench.addClass('nopanel');
		}
E
Erich Gamma 已提交
1125

B
Benjamin Pasero 已提交
1126
		// Apply font aliasing
1127 1128
		this.setFontAliasing(this.fontAliasing);

B
Benjamin Pasero 已提交
1129
		// Apply title style if shown
1130 1131 1132 1133 1134 1135 1136 1137
		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 已提交
1138 1139
		}

E
Erich Gamma 已提交
1140
		// Create Parts
B
Benjamin Pasero 已提交
1141
		this.createTitlebarPart();
E
Erich Gamma 已提交
1142 1143 1144
		this.createActivityBarPart();
		this.createSidebarPart();
		this.createEditorPart();
1145
		this.createPanelPart();
E
Erich Gamma 已提交
1146 1147 1148 1149 1150 1151
		this.createStatusbarPart();

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

B
Benjamin Pasero 已提交
1152 1153 1154 1155 1156 1157 1158 1159 1160 1161
	private createTitlebarPart(): void {
		const titlebarContainer = $(this.workbench).div({
			'class': ['part', 'titlebar'],
			id: Identifiers.TITLEBAR_PART,
			role: 'contentinfo'
		});

		this.titlebarPart.create(titlebarContainer);
	}

E
Erich Gamma 已提交
1162
	private createActivityBarPart(): void {
B
Benjamin Pasero 已提交
1163
		const activitybarPartContainer = $(this.workbench)
E
Erich Gamma 已提交
1164 1165
			.div({
				'class': ['part', 'activitybar', this.sideBarPosition === Position.LEFT ? 'left' : 'right'],
1166 1167
				id: Identifiers.ACTIVITYBAR_PART,
				role: 'navigation'
E
Erich Gamma 已提交
1168 1169 1170 1171 1172 1173
			});

		this.activitybarPart.create(activitybarPartContainer);
	}

	private createSidebarPart(): void {
B
Benjamin Pasero 已提交
1174
		const sidebarPartContainer = $(this.workbench)
E
Erich Gamma 已提交
1175 1176
			.div({
				'class': ['part', 'sidebar', this.sideBarPosition === Position.LEFT ? 'left' : 'right'],
1177 1178
				id: Identifiers.SIDEBAR_PART,
				role: 'complementary'
E
Erich Gamma 已提交
1179 1180 1181 1182 1183
			});

		this.sidebarPart.create(sidebarPartContainer);
	}

I
isidor 已提交
1184
	private createPanelPart(): void {
B
Benjamin Pasero 已提交
1185
		const panelPartContainer = $(this.workbench)
I
isidor 已提交
1186
			.div({
1187
				'class': ['part', 'panel'],
1188 1189
				id: Identifiers.PANEL_PART,
				role: 'complementary'
I
isidor 已提交
1190 1191 1192 1193 1194
			});

		this.panelPart.create(panelPartContainer);
	}

E
Erich Gamma 已提交
1195
	private createEditorPart(): void {
B
Benjamin Pasero 已提交
1196
		const editorContainer = $(this.workbench)
E
Erich Gamma 已提交
1197
			.div({
1198
				'class': ['part', 'editor', 'empty'],
1199 1200
				id: Identifiers.EDITOR_PART,
				role: 'main'
E
Erich Gamma 已提交
1201 1202 1203 1204 1205 1206
			});

		this.editorPart.create(editorContainer);
	}

	private createStatusbarPart(): void {
B
Benjamin Pasero 已提交
1207
		const statusbarContainer = $(this.workbench).div({
E
Erich Gamma 已提交
1208
			'class': ['part', 'statusbar'],
1209 1210
			id: Identifiers.STATUSBAR_PART,
			role: 'contentinfo'
E
Erich Gamma 已提交
1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227
		});

		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 已提交
1228 1229 1230 1231 1232 1233
	public getPanelPart(): PanelPart {
		assert.ok(this.workbenchStarted, 'Workbench is not started. Call startup() first.');

		return this.panelPart;
	}

E
Erich Gamma 已提交
1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250
	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);
		}
	}
1251 1252 1253 1254

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

I
isidor 已提交
1256
	public toggleZenMode(skipLayout?: boolean): void {
I
isidor 已提交
1257 1258
		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
1259
		let toggleFullScreen = false;
I
isidor 已提交
1260
		if (this.zenMode.active) {
I
isidor 已提交
1261 1262
			const config = this.configurationService.getConfiguration<IZenModeSettings>('zenMode');
			toggleFullScreen = !browser.isFullscreen() && config.fullScreen;
I
isidor 已提交
1263
			this.zenMode.transitionedToFullScreen = toggleFullScreen;
1264 1265
			this.zenMode.wasSideBarVisible = this.isVisible(Parts.SIDEBAR_PART);
			this.zenMode.wasPanelVisible = this.isVisible(Parts.PANEL_PART);
1266
			this.setPanelHidden(true, true).done(undefined, errors.onUnexpectedError);
1267
			this.setSideBarHidden(true, true).done(undefined, errors.onUnexpectedError);
I
isidor 已提交
1268

1269 1270 1271
			if (config.hideActivityBar) {
				this.setActivityBarHidden(true, true);
			}
I
isidor 已提交
1272
			if (config.hideStatusBar) {
I
isidor 已提交
1273 1274
				this.setStatusBarHidden(true, true);
			}
I
isidor 已提交
1275
			if (config.hideTabs) {
I
isidor 已提交
1276 1277
				this.editorPart.hideTabs(true);
			}
1278
		} else {
1279
			if (this.zenMode.wasPanelVisible) {
1280
				this.setPanelHidden(false, true).done(undefined, errors.onUnexpectedError);
1281
			}
1282
			if (this.zenMode.wasSideBarVisible) {
1283
				this.setSideBarHidden(false, true).done(undefined, errors.onUnexpectedError);
1284
			}
1285 1286
			// Status bar and activity bar visibility come from settings -> update their visibility.
			this.onDidUpdateConfiguration(true);
I
isidor 已提交
1287
			this.editorPart.hideTabs(false);
I
isidor 已提交
1288 1289 1290 1291
			const activeEditor = this.editorPart.getActiveEditor();
			if (activeEditor) {
				activeEditor.focus();
			}
1292
			toggleFullScreen = this.zenMode.transitionedToFullScreen && browser.isFullscreen();
I
isidor 已提交
1293
		}
1294
		this.inZenMode.set(this.zenMode.active);
I
isidor 已提交
1295

I
isidor 已提交
1296
		if (!skipLayout) {
1297
			this.layout();
I
isidor 已提交
1298
		}
1299 1300 1301
		if (toggleFullScreen) {
			this.windowService.toggleFullScreen().done(undefined, errors.onUnexpectedError);
		}
I
isidor 已提交
1302 1303
	}

1304 1305 1306 1307 1308 1309 1310 1311 1312 1313
	// 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 已提交
1314
				return; // Cannot resize other parts
1315 1316 1317 1318
		}
	}


1319
	private shouldRestoreLastOpenedViewlet(): boolean {
1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330
		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 已提交
1331
}