workbench.ts 50.6 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 { IEditorInputFactoryRegistry, 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
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';
I
isidor 已提交
42
import { Position, Parts, IPartService, ILayoutOptions } from 'vs/workbench/services/part/common/partService';
43
import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace';
J
Johannes Rieken 已提交
44 45 46 47
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';
48
import { WorkspaceService, DefaultConfigurationExportHelper } from 'vs/workbench/services/configuration/node/configurationService';
49 50
import { IJSONEditingService } from 'vs/workbench/services/configuration/common/jsonEditing';
import { JSONEditingService } from 'vs/workbench/services/configuration/node/jsonEditingService';
J
Johannes Rieken 已提交
51 52
import { ContextKeyService } from 'vs/platform/contextkey/browser/contextKeyService';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
53
import { IKeybindingEditingService, KeybindingsEditingService } from 'vs/workbench/services/keybinding/common/keybindingEditing';
J
Johannes Rieken 已提交
54
import { ContextKeyExpr, RawContextKey, IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey';
55
import { IActivityBarService } from 'vs/workbench/services/activity/common/activityBarService';
B
Benjamin Pasero 已提交
56
import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet';
P
Pine Wu 已提交
57
import { ViewletService } from 'vs/workbench/services/viewlet/browser/viewletService';
58
import { RemoteFileService } from 'vs/workbench/services/files/electron-browser/remoteFileService';
J
Johannes Rieken 已提交
59
import { IFileService } from 'vs/platform/files/common/files';
60
import { IListService, ListService } from 'vs/platform/list/browser/listService';
J
Johannes Rieken 已提交
61 62 63
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 已提交
64
import { ITitleService } from 'vs/workbench/services/title/common/titleService';
J
Johannes Rieken 已提交
65
import { WorkbenchMessageService } from 'vs/workbench/services/message/browser/messageService';
B
Benjamin Pasero 已提交
66
import { IWorkbenchEditorService, IResourceInputType, WorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService';
J
Johannes Rieken 已提交
67
import { IQuickOpenService } from 'vs/platform/quickOpen/common/quickOpen';
68 69
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
import { ClipboardService } from 'vs/platform/clipboard/electron-browser/clipboardService';
J
Johannes Rieken 已提交
70 71 72 73 74 75
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 已提交
76 77
import { ISCMService } from 'vs/workbench/services/scm/common/scm';
import { SCMService } from 'vs/workbench/services/scm/common/scmService';
78 79
import { IProgressService2 } from 'vs/platform/progress/common/progress';
import { ProgressService2 } from 'vs/workbench/services/progress/browser/progressService2';
80
import { TextModelResolverService } from 'vs/workbench/services/textmodelResolver/common/textModelResolverService';
81
import { ITextModelService } from 'vs/editor/common/services/resolverService';
J
Johannes Rieken 已提交
82
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
83
import { ILifecycleService, ShutdownReason } from 'vs/platform/lifecycle/common/lifecycle';
B
Benjamin Pasero 已提交
84
import { IWindowService, IWindowConfiguration as IWindowSettings, IWindowConfiguration, IPath } from 'vs/platform/windows/common/windows';
J
Johannes Rieken 已提交
85 86
import { IMessageService } from 'vs/platform/message/common/message';
import { IStatusbarService } from 'vs/platform/statusbar/common/statusbar';
87
import { IMenuService, SyncActionDescriptor } from 'vs/platform/actions/common/actions';
J
Johannes Rieken 已提交
88 89 90 91
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';
B
Benjamin Pasero 已提交
92
import { IWorkbenchActionRegistry, Extensions } from 'vs/workbench/common/actions';
93
import { OpenRecentAction, ToggleDevToolsAction, ReloadWindowAction, ShowPreviousWindowTab, MoveWindowTabToNewWindow, MergeAllWindowTabs, ShowNextWindowTab, ToggleWindowTabsBar } from 'vs/workbench/electron-browser/actions';
94
import { KeyMod, KeyCode } from 'vs/base/common/keyCodes';
95
import { IWorkspaceEditingService } from 'vs/workbench/services/workspace/common/workspaceEditing';
B
Benjamin Pasero 已提交
96
import { WorkspaceEditingService } from 'vs/workbench/services/workspace/node/workspaceEditingService';
97
import { FileDecorationsService } from 'vs/workbench/services/decorations/browser/decorationsService';
J
Johannes Rieken 已提交
98
import { IDecorationsService } from 'vs/workbench/services/decorations/browser/decorations';
B
Benjamin Pasero 已提交
99
import URI from 'vs/base/common/uri';
100

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

E
Erich Gamma 已提交
106
interface WorkbenchParams {
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 static closeWhenEmptyConfigurationKey = 'window.closeWhenEmpty';

159 160
	private static fontAliasingConfigurationKey = 'workbench.fontAliasing';

161 162
	private _onTitleBarVisibilityChange: Emitter<void>;

163
	public _serviceBrand: any;
E
Erich Gamma 已提交
164

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

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

		this.workbenchParams = {
230
			configuration,
231
			serviceCollection
E
Erich Gamma 已提交
232 233
		};

234
		this.hasFilesToCreateOpenOrDiff =
B
Benjamin Pasero 已提交
235 236 237
			(configuration.filesToCreate && configuration.filesToCreate.length > 0) ||
			(configuration.filesToOpen && configuration.filesToOpen.length > 0) ||
			(configuration.filesToDiff && configuration.filesToDiff.length > 0);
238

E
Erich Gamma 已提交
239 240
		this.toDispose = [];
		this.toShutdown = [];
241

E
Erich Gamma 已提交
242
		this.editorBackgroundDelayer = new Delayer<void>(50);
243
		this.closeEmptyWindowScheduler = new RunOnceScheduler(() => this.onAllEditorsClosed(), 50);
E
Erich Gamma 已提交
244

245 246
		this._onTitleBarVisibilityChange = new Emitter<void>();

247
		this.creationPromise = new TPromise<boolean>(c => {
E
Erich Gamma 已提交
248 249 250 251
			this.creationPromiseComplete = c;
		});
	}

252 253 254 255
	public get onTitleBarVisibilityChange(): Event<void> {
		return this._onTitleBarVisibilityChange.event;
	}

256 257 258 259 260 261
	public get onEditorLayout(): Event<void> {
		return chain(this.editorPart.onLayout)
			.map(() => void 0)
			.event;
	}

E
Erich Gamma 已提交
262 263 264 265 266 267 268 269 270 271 272 273 274 275 276
	/**
	 * 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();

277 278 279
			// Install some global actions
			this.createGlobalActions();

E
Erich Gamma 已提交
280 281 282 283 284 285
			// Services
			this.initServices();
			if (this.callbacks && this.callbacks.onServicesCreated) {
				this.callbacks.onServicesCreated();
			}

286
			// Contexts
287 288
			this.messagesVisibleContext = MessagesVisibleContext.bindTo(this.contextKeyService);
			this.editorsVisibleContext = EditorsVisibleContext.bindTo(this.contextKeyService);
I
isidor 已提交
289
			this.inZenMode = InZenModeContext.bindTo(this.contextKeyService);
290

E
Erich Gamma 已提交
291 292 293 294 295 296 297 298 299 300 301 302
			// Register Listeners
			this.registerListeners();

			// Settings
			this.initSettings();

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

			// Workbench Layout
			this.createWorkbenchLayout();

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

P
Pine Wu 已提交
306
			// Restore last opened viewlet
307
			let viewletRestoreStopWatch: StopWatch;
308
			let viewletIdToRestore: string;
309
			if (!this.sideBarHidden) {
310

311
				if (this.shouldRestoreLastOpenedViewlet()) {
312
					viewletIdToRestore = this.storageService.get(SidebarPart.activeViewletSettingsKey, StorageScope.WORKSPACE);
B
polish  
Benjamin Pasero 已提交
313 314 315
				}

				if (!viewletIdToRestore) {
316
					viewletIdToRestore = this.viewletService.getDefaultViewletId();
P
Pine Wu 已提交
317
				}
318

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

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

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

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

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

361
			if (this.storageService.getBoolean(Workbench.zenModeActiveSettingKey, StorageScope.WORKSPACE, false)) {
I
isidor 已提交
362 363 364
				this.toggleZenMode(true);
			}

E
Erich Gamma 已提交
365
			// Flag workbench as created once done
366
			const workbenchDone = (error?: Error) => {
E
Erich Gamma 已提交
367 368 369
				this.workbenchCreated = true;
				this.creationPromiseComplete(true);

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

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

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

			// Print out error
391
			console.error(toErrorMessage(error, true));
E
Erich Gamma 已提交
392 393 394 395 396 397

			// Rethrow
			throw error;
		}
	}

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

B
Benjamin Pasero 已提交
401
		// Actions registered here to adjust for developing vs built workbench
402 403
		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 已提交
404
		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 已提交
405
		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"));
406

407
		// Actions for macOS native tabs management (only when enabled)
408
		const windowConfig = this.configurationService.getConfiguration<IWindowConfiguration>();
409 410 411 412 413 414 415
		if (windowConfig && windowConfig.window && windowConfig.window.nativeTabs) {
			workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(ShowPreviousWindowTab, ShowPreviousWindowTab.ID, ShowPreviousWindowTab.LABEL), 'Show Previous Window Tab');
			workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(ShowNextWindowTab, ShowNextWindowTab.ID, ShowNextWindowTab.LABEL), 'Show Next Window Tab');
			workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(MoveWindowTabToNewWindow, MoveWindowTabToNewWindow.ID, MoveWindowTabToNewWindow.LABEL), 'Move Window Tab to New Window');
			workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(MergeAllWindowTabs, MergeAllWindowTabs.ID, MergeAllWindowTabs.LABEL), 'Merge All Windows');
			workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(ToggleWindowTabsBar, ToggleWindowTabsBar.ID, ToggleWindowTabsBar.LABEL), 'Toggle Window Tabs Bar');
		}
416 417
	}

418
	private resolveEditorsToOpen(): TPromise<IResourceInputType[]> {
419
		const config = this.workbenchParams.configuration;
B
Benjamin Pasero 已提交
420 421

		// Files to open, diff or create
422
		if (this.hasFilesToCreateOpenOrDiff) {
B
Benjamin Pasero 已提交
423 424

			// Files to diff is exclusive
425
			const filesToDiff = this.toInputs(config.filesToDiff, false);
426
			if (filesToDiff && filesToDiff.length === 2) {
427 428 429 430 431
				return TPromise.as([<IResourceDiffInput>{
					leftResource: filesToDiff[0].resource,
					rightResource: filesToDiff[1].resource,
					options: { pinned: true }
				}]);
B
Benjamin Pasero 已提交
432 433
			}

434 435
			const filesToCreate = this.toInputs(config.filesToCreate, true);
			const filesToOpen = this.toInputs(config.filesToOpen, false);
436

437 438
			// Otherwise: Open/Create files
			return TPromise.as([...filesToOpen, ...filesToCreate]);
B
Benjamin Pasero 已提交
439 440
		}

441
		// Empty workbench
442
		else if (this.contextService.getWorkbenchState() === WorkbenchState.EMPTY && this.openUntitledFile()) {
443 444 445 446
			if (this.editorPart.hasEditorsToRestore()) {
				return TPromise.as([]); // do not open any empty untitled file if we have editors to restore
			}

447 448 449 450 451
			return this.backupFileService.hasBackups().then(hasBackups => {
				if (hasBackups) {
					return TPromise.as([]); // do not open any empty untitled file if we have backups to restore
				}

452
				return TPromise.as([<IUntitledResourceInput>{}]);
453
			});
B
Benjamin Pasero 已提交
454 455 456 457 458
		}

		return TPromise.as([]);
	}

459
	private toInputs(paths: IPath[], isNew: boolean): (IResourceInput | IUntitledResourceInput)[] {
B
Benjamin Pasero 已提交
460 461 462 463 464
		if (!paths || !paths.length) {
			return [];
		}

		return paths.map(p => {
465 466 467 468 469 470 471
			const resource = URI.file(p.filePath);
			let input: IResourceInput | IUntitledResourceInput;
			if (isNew) {
				input = { filePath: resource.fsPath, options: { pinned: true } } as IUntitledResourceInput;
			} else {
				input = { resource, options: { pinned: true } } as IResourceInput;
			}
B
Benjamin Pasero 已提交
472

473
			if (!isNew && p.lineNumber) {
B
Benjamin Pasero 已提交
474 475 476 477 478 479 480 481 482 483
				input.options.selection = {
					startLineNumber: p.lineNumber,
					startColumn: p.columnNumber
				};
			}

			return input;
		});
	}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

555 556 557 558 559
		// File Service
		this.fileService = this.instantiationService.createInstance(RemoteFileService);
		serviceCollection.set(IFileService, this.fileService);
		this.toDispose.push(this.fileService.onFileChanges(e => this.configurationService.handleWorkspaceFileEvents(e)));

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

568 569 570 571 572 573
		// 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);

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

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

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

584
		// File Decorations
J
Johannes Rieken 已提交
585
		serviceCollection.set(IDecorationsService, new SyncDescriptor(FileDecorationsService));
586

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

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

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

597 598 599
		// Workspace Editing
		serviceCollection.set(IWorkspaceEditingService, new SyncDescriptor(WorkspaceEditingService));

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

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

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

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

		// Set the some services to registries that have been created eagerly
619 620
		Registry.as<IActionBarRegistry>(ActionBarExtensions.Actionbar).setInstantiationService(this.instantiationService);
		Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench).setInstantiationService(this.instantiationService);
621
		Registry.as<IEditorInputFactoryRegistry>(EditorExtensions.EditorInputFactories).setInstantiationService(this.instantiationService);
622

623
		this.instantiationService.createInstance(DefaultConfigurationExportHelper);
624 625

		this.configurationService.setInstantiationService(this.getInstantiationService());
E
Erich Gamma 已提交
626 627 628 629 630
	}

	private initSettings(): void {

		// Sidebar visibility
631
		this.sideBarHidden = this.storageService.getBoolean(Workbench.sidebarHiddenSettingKey, StorageScope.WORKSPACE, this.contextService.getWorkbenchState() === WorkbenchState.EMPTY);
E
Erich Gamma 已提交
632

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

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

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

		// Activity bar visibility
649
		const activityBarVisible = this.configurationService.getValue<string>(Workbench.activityBarVisibleConfigurationKey);
S
Sanders Lauture 已提交
650
		this.activityBarHidden = !activityBarVisible;
I
isidor 已提交
651

652
		// Font aliasing
653
		this.fontAliasing = this.configurationService.getValue<string>(Workbench.fontAliasingConfigurationKey);
654

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

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

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

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

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

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

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

		return offset;
	}

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

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

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

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

		return null;
B
Benjamin Pasero 已提交
767 768
	}

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

I
isidor 已提交
772

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

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

I
isidor 已提交
782

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

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

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

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

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

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

823
		return promise.then(() => {
824

825
			// Remember in settings
826
			const defaultHidden = this.contextService.getWorkbenchState() === WorkbenchState.EMPTY;
827 828 829 830 831
			if (hidden !== defaultHidden) {
				this.storageService.store(Workbench.sidebarHiddenSettingKey, hidden ? 'true' : 'false', StorageScope.WORKSPACE);
			} else {
				this.storageService.remove(Workbench.sidebarHiddenSettingKey, StorageScope.WORKSPACE);
			}
832 833 834

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

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

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

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

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

870
		return promise.then(() => {
871

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

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

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

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

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

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

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

913 914 915 916
		// Update Styles
		this.activitybarPart.updateStyles();
		this.sidebarPart.updateStyles();

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

921 922
	private setFontAliasing(aliasing: string) {
		this.fontAliasing = aliasing;
B
Benjamin Pasero 已提交
923

924 925 926
		document.body.style['-webkit-font-smoothing'] = (aliasing === 'default' ? '' : aliasing);
	}

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

J
Joao Moreno 已提交
933
		this.toDispose = dispose(this.toDispose);
E
Erich Gamma 已提交
934 935 936 937 938 939
	}

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

946 947 948 949 950 951
	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 已提交
952

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

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

	private registerListeners(): void {

		// Listen to editor changes
969
		this.toDispose.push(this.editorPart.onEditorsChanged(() => this.onEditorsChanged()));
970

971 972 973 974 975 976 977 978 979 980
		// Listen to editor closing (if we run with --wait)
		const filesToWait = this.workbenchParams.configuration.filesToWait;
		if (filesToWait) {
			const resourcesToWaitFor = filesToWait.paths.map(p => URI.file(p.filePath));
			const waitMarkerFile = URI.file(filesToWait.waitMarkerFilePath);
			const listenerDispose = this.editorPart.getStacksModel().onEditorClosed(() => this.onEditorClosed(listenerDispose, resourcesToWaitFor, waitMarkerFile));

			this.toDispose.push(listenerDispose);
		}

981
		// Handle message service and quick open events
982 983
		this.toDispose.push((<WorkbenchMessageService>this.messageService).onMessagesShowing(() => this.messagesVisibleContext.set(true)));
		this.toDispose.push((<WorkbenchMessageService>this.messageService).onMessagesCleared(() => this.messagesVisibleContext.reset()));
984

985 986 987 988
		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
989
		this.toDispose.push(this.configurationService.onDidChangeConfiguration(() => this.onDidUpdateConfiguration()));
990 991 992 993 994 995 996 997 998 999

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

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

1000
		// Apply as CSS class
1001 1002 1003 1004 1005
		const isFullscreen = browser.isFullscreen();
		if (isFullscreen) {
			this.addClass('fullscreen');
		} else {
			this.removeClass('fullscreen');
I
isidor 已提交
1006 1007
			if (this.zenMode.transitionedToFullScreen && this.zenMode.active) {
				this.toggleZenMode();
I
isidor 已提交
1008
			}
1009
		}
1010

1011 1012 1013 1014 1015
		// 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
1016
		}
E
Erich Gamma 已提交
1017 1018
	}

1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030
	private onEditorClosed(listenerDispose: IDisposable, resourcesToWaitFor: URI[], waitMarkerFile: URI): void {

		// In wait mode, listen to changes to the editors and wait until the files
		// are closed that the user wants to wait for. When this happens we delete
		// the wait marker file to signal to the outside that editing is done.
		const stacks = this.editorPart.getStacksModel();
		if (resourcesToWaitFor.every(r => !stacks.isOpen(r))) {
			listenerDispose.dispose();
			this.fileService.del(waitMarkerFile).done(null, errors.onUnexpectedError);
		}
	}

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

1034 1035
		// 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
1036
		// or setting is disabled. Also enabled when running with --wait from the command line.
1037
		if (visibleEditors === 0 && this.contextService.getWorkbenchState() === WorkbenchState.EMPTY && !this.environmentService.isExtensionDevelopment) {
1038
			const closeWhenEmpty = this.configurationService.getValue<boolean>(Workbench.closeWhenEmptyConfigurationKey);
1039
			if (closeWhenEmpty || this.environmentService.args.wait) {
1040 1041 1042 1043
				this.closeEmptyWindowScheduler.schedule();
			}
		}

E
Erich Gamma 已提交
1044 1045
		// 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 已提交
1046 1047 1048 1049 1050 1051
		this.handleEditorBackground();
	}

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

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

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

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

1076
		const fontAliasing = this.configurationService.getValue<string>(Workbench.fontAliasingConfigurationKey);
1077 1078 1079 1080
		if (fontAliasing !== this.fontAliasing) {
			this.setFontAliasing(fontAliasing);
		}

1081
		if (!this.zenMode.active) {
1082
			const newStatusbarHiddenValue = !this.configurationService.getValue<boolean>(Workbench.statusbarVisibleConfigurationKey);
1083 1084 1085
			if (newStatusbarHiddenValue !== this.statusBarHidden) {
				this.setStatusBarHidden(newStatusbarHiddenValue, skipLayout);
			}
S
Sanders Lauture 已提交
1086

1087
			const newActivityBarHiddenValue = !this.configurationService.getValue<boolean>(Workbench.activityBarVisibleConfigurationKey);
1088 1089 1090
			if (newActivityBarHiddenValue !== this.activityBarHidden) {
				this.setActivityBarHidden(newActivityBarHiddenValue, skipLayout);
			}
S
Sanders Lauture 已提交
1091
		}
1092 1093
	}

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

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

	private createWorkbench(): void {

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

	private renderWorkbench(): void {

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

B
Benjamin Pasero 已提交
1129
		// Apply font aliasing
1130 1131
		this.setFontAliasing(this.fontAliasing);

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

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

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

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

		this.titlebarPart.create(titlebarContainer);
	}

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

		this.activitybarPart.create(activitybarPartContainer);
	}

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

		this.sidebarPart.create(sidebarPartContainer);
	}

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

		this.panelPart.create(panelPartContainer);
	}

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

		this.editorPart.create(editorContainer);
	}

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

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

		return this.panelPart;
	}

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

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

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

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

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

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


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