workbench.ts 59.8 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';
11
import { TPromise } from 'vs/base/common/winjs.base';
12
import { IDisposable, dispose, toDisposable, Disposable } from 'vs/base/common/lifecycle';
M
Matt Bierner 已提交
13
import { Event, Emitter } from 'vs/base/common/event';
14
import * as DOM from 'vs/base/browser/dom';
15
import { RunOnceScheduler } from 'vs/base/common/async';
16
import * as browser from 'vs/base/browser/browser';
J
Johannes Rieken 已提交
17
import * as perf from 'vs/base/common/performance';
18
import * as errors from 'vs/base/common/errors';
B
Benjamin Pasero 已提交
19
import { BackupFileService, InMemoryBackupFileService } from 'vs/workbench/services/backup/node/backupFileService';
20
import { IBackupFileService } from 'vs/workbench/services/backup/common/backup';
21
import { Registry } from 'vs/platform/registry/common/platform';
B
Benjamin Pasero 已提交
22
import { isWindows, isLinux, isMacintosh } from 'vs/base/common/platform';
23
import { IResourceInput } from 'vs/platform/editor/common/editor';
J
Johannes Rieken 已提交
24
import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions';
25
import { IEditorInputFactoryRegistry, Extensions as EditorExtensions, TextCompareEditorVisibleContext, TEXT_DIFF_EDITOR_ID, EditorsVisibleContext, InEditorZenModeContext, ActiveEditorGroupEmptyContext, MultipleEditorGroupsContext, IUntitledResourceInput, IResourceDiffInput, SplitEditorsVertically, TextCompareEditorActiveContext } from 'vs/workbench/common/editor';
26
import { HistoryService } from 'vs/workbench/services/history/electron-browser/history';
J
Johannes Rieken 已提交
27 28 29 30
import { ActivitybarPart } from 'vs/workbench/browser/parts/activitybar/activitybarPart';
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 已提交
31
import { TitlebarPart } from 'vs/workbench/browser/parts/titlebar/titlebarPart';
32
import { EditorPart } from 'vs/workbench/browser/parts/editor/editorPart';
B
Benjamin Pasero 已提交
33
import { WorkbenchLayout } from 'vs/workbench/browser/layout';
34
import { IActionBarRegistry, Extensions as ActionBarExtensions } from 'vs/workbench/browser/actions';
J
Johannes Rieken 已提交
35 36
import { PanelRegistry, Extensions as PanelExtensions } from 'vs/workbench/browser/panel';
import { QuickOpenController } from 'vs/workbench/browser/parts/quickopen/quickOpenController';
C
Christof Marti 已提交
37 38
import { IQuickInputService } from 'vs/platform/quickinput/common/quickInput';
import { QuickInputService } from 'vs/workbench/browser/parts/quickinput/quickInput';
J
Johannes Rieken 已提交
39
import { getServices } from 'vs/platform/instantiation/common/extensions';
40
import { Position, Parts, IPartService, ILayoutOptions, IDimension } from 'vs/workbench/services/part/common/partService';
41
import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace';
J
Johannes Rieken 已提交
42
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
S
SteVen Batten 已提交
43 44
import { ContextMenuService as NativeContextMenuService } from 'vs/workbench/services/contextview/electron-browser/contextmenuService';
import { ContextMenuService as HTMLContextMenuService } from 'vs/platform/contextview/browser/contextMenuService';
J
Johannes Rieken 已提交
45 46
import { WorkbenchKeybindingService } from 'vs/workbench/services/keybinding/electron-browser/keybindingService';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
47
import { WorkspaceService, DefaultConfigurationExportHelper } from 'vs/workbench/services/configuration/node/configurationService';
48 49
import { IJSONEditingService } from 'vs/workbench/services/configuration/common/jsonEditing';
import { JSONEditingService } from 'vs/workbench/services/configuration/node/jsonEditingService';
J
Johannes Rieken 已提交
50
import { ContextKeyService } from 'vs/platform/contextkey/browser/contextKeyService';
51 52
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { IKeybindingEditingService, KeybindingsEditingService } from 'vs/workbench/services/keybinding/common/keybindingEditing';
53
import { RawContextKey, IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey';
I
isidor 已提交
54
import { IActivityService } from 'vs/workbench/services/activity/common/activity';
B
Benjamin Pasero 已提交
55
import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet';
P
Pine Wu 已提交
56
import { ViewletService } from 'vs/workbench/services/viewlet/browser/viewletService';
57
import { RemoteFileService } from 'vs/workbench/services/files/electron-browser/remoteFileService';
J
Johannes Rieken 已提交
58 59
import { IFileService } from 'vs/platform/files/common/files';
import { IConfigurationResolverService } from 'vs/workbench/services/configurationResolver/common/configurationResolver';
60
import { ConfigurationResolverService } from 'vs/workbench/services/configurationResolver/electron-browser/configurationResolverService';
J
Johannes Rieken 已提交
61
import { IPanelService } from 'vs/workbench/services/panel/common/panelService';
B
Benjamin Pasero 已提交
62
import { ITitleService } from 'vs/workbench/services/title/common/titleService';
J
Johannes Rieken 已提交
63
import { IQuickOpenService } from 'vs/platform/quickOpen/common/quickOpen';
64 65
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
import { ClipboardService } from 'vs/platform/clipboard/electron-browser/clipboardService';
J
Johannes Rieken 已提交
66 67 68 69 70
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 已提交
71 72
import { ISCMService } from 'vs/workbench/services/scm/common/scm';
import { SCMService } from 'vs/workbench/services/scm/common/scmService';
73
import { IProgressService2 } from 'vs/workbench/services/progress/common/progress';
74
import { ProgressService2 } from 'vs/workbench/services/progress/browser/progressService2';
75
import { TextModelResolverService } from 'vs/workbench/services/textmodelResolver/common/textModelResolverService';
76
import { ITextModelService } from 'vs/editor/common/services/resolverService';
J
Johannes Rieken 已提交
77
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
B
Benjamin Pasero 已提交
78
import { ShutdownReason } from 'vs/platform/lifecycle/common/lifecycle';
79
import { LifecycleService } from 'vs/platform/lifecycle/electron-browser/lifecycleService';
80
import { IWindowService, IWindowConfiguration as IWindowSettings, IWindowConfiguration, IPath, MenuBarVisibility } from 'vs/platform/windows/common/windows';
J
Johannes Rieken 已提交
81
import { IStatusbarService } from 'vs/platform/statusbar/common/statusbar';
82
import { IMenuService, SyncActionDescriptor } from 'vs/platform/actions/common/actions';
83
import { MenuService } from 'vs/workbench/services/actions/common/menuService';
S
SteVen Batten 已提交
84
import { IContextMenuService, IContextViewService } from 'vs/platform/contextview/browser/contextView';
J
Johannes Rieken 已提交
85
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
B
Benjamin Pasero 已提交
86
import { IWorkbenchActionRegistry, Extensions } from 'vs/workbench/common/actions';
87
import { OpenRecentAction, ToggleDevToolsAction, ReloadWindowAction, ShowPreviousWindowTab, MoveWindowTabToNewWindow, MergeAllWindowTabs, ShowNextWindowTab, ToggleWindowTabsBar, ReloadWindowWithExtensionsDisabledAction, NewWindowTab } from 'vs/workbench/electron-browser/actions';
88
import { KeyMod, KeyCode } from 'vs/base/common/keyCodes';
89
import { IWorkspaceEditingService } from 'vs/workbench/services/workspace/common/workspaceEditing';
B
Benjamin Pasero 已提交
90
import { WorkspaceEditingService } from 'vs/workbench/services/workspace/node/workspaceEditingService';
91
import { FileDecorationsService } from 'vs/workbench/services/decorations/browser/decorationsService';
J
Johannes Rieken 已提交
92
import { IDecorationsService } from 'vs/workbench/services/decorations/browser/decorations';
I
isidor 已提交
93
import { ActivityService } from 'vs/workbench/services/activity/browser/activityService';
B
Benjamin Pasero 已提交
94
import URI from 'vs/base/common/uri';
J
Joao Moreno 已提交
95
import { IListService, ListService } from 'vs/platform/list/browser/listService';
J
Joao Moreno 已提交
96
import { InputFocusedContext } from 'vs/platform/workbench/common/contextkeys';
97
import { IViewsService } from 'vs/workbench/common/views';
S
Sandeep Somavarapu 已提交
98
import { ViewsService } from 'vs/workbench/browser/parts/views/views';
99 100
import { INotificationService } from 'vs/platform/notification/common/notification';
import { NotificationService } from 'vs/workbench/services/notification/common/notificationService';
101 102
import { NotificationsCenter } from 'vs/workbench/browser/parts/notifications/notificationsCenter';
import { NotificationsAlerts } from 'vs/workbench/browser/parts/notifications/notificationsAlerts';
103
import { NotificationsStatus } from 'vs/workbench/browser/parts/notifications/notificationsStatus';
104
import { registerNotificationCommands } from 'vs/workbench/browser/parts/notifications/notificationsCommands';
105
import { NotificationsToasts } from 'vs/workbench/browser/parts/notifications/notificationsToasts';
J
Joao Moreno 已提交
106
import { IPCClient } from 'vs/base/parts/ipc/node/ipc';
J
Joao Moreno 已提交
107
import { registerWindowDriver } from 'vs/platform/driver/electron-browser/driver';
S
Sandeep Somavarapu 已提交
108 109
import { IPreferencesService } from 'vs/workbench/services/preferences/common/preferences';
import { PreferencesService } from 'vs/workbench/services/preferences/browser/preferencesService';
110
import { IEditorService, IResourceEditor } from 'vs/workbench/services/editor/common/editorService';
I
isidor 已提交
111
import { IEditorGroupsService, GroupDirection, preferredSideBySideGroupDirection } from 'vs/workbench/services/group/common/editorGroupsService';
112
import { EditorService } from 'vs/workbench/services/editor/browser/editorService';
J
Joao Moreno 已提交
113
import { IExtensionUrlHandler, ExtensionUrlHandler } from 'vs/platform/url/electron-browser/inactiveExtensionUrlHandler';
S
SteVen Batten 已提交
114
import { ContextViewService } from 'vs/platform/contextview/browser/contextViewService';
S
SteVen Batten 已提交
115 116
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { TelemetryService } from 'vs/platform/telemetry/common/telemetryService';
A
Alex Dima 已提交
117 118
import { WorkbenchThemeService } from 'vs/workbench/services/themes/electron-browser/workbenchThemeService';
import { IWorkbenchThemeService } from 'vs/workbench/services/themes/common/workbenchThemeService';
119

E
Erich Gamma 已提交
120
interface WorkbenchParams {
121
	configuration: IWindowConfiguration;
122
	serviceCollection: ServiceCollection;
E
Erich Gamma 已提交
123 124
}

I
isidor 已提交
125 126
interface IZenModeSettings {
	fullScreen: boolean;
127
	centerLayout: boolean;
I
isidor 已提交
128
	hideTabs: boolean;
129
	hideActivityBar: boolean;
I
isidor 已提交
130
	hideStatusBar: boolean;
I
isidor 已提交
131
	restore: boolean;
I
isidor 已提交
132 133
}

134 135 136
export interface IWorkbenchStartedInfo {
	customKeybindingsCount: number;
	pinnedViewlets: string[];
137
	restoredViewlet: string;
138
	restoredEditorsCount: number;
139 140
}

141 142
type FontAliasingOption = 'default' | 'antialiased' | 'none' | 'auto';

B
Benjamin Pasero 已提交
143 144
const fontAliasingValues: FontAliasingOption[] = ['antialiased', 'none', 'auto'];

145 146
const Identifiers = {
	WORKBENCH_CONTAINER: 'workbench.main.container',
B
Benjamin Pasero 已提交
147
	TITLEBAR_PART: 'workbench.parts.titlebar',
148 149 150 151
	ACTIVITYBAR_PART: 'workbench.parts.activitybar',
	SIDEBAR_PART: 'workbench.parts.sidebar',
	PANEL_PART: 'workbench.parts.panel',
	EDITOR_PART: 'workbench.parts.editor',
S
SteVen Batten 已提交
152
	STATUSBAR_PART: 'workbench.parts.statusbar'
153 154
};

J
Joao Moreno 已提交
155 156 157 158 159 160 161 162
function getWorkbenchStateString(state: WorkbenchState): string {
	switch (state) {
		case WorkbenchState.EMPTY: return 'empty';
		case WorkbenchState.FOLDER: return 'folder';
		case WorkbenchState.WORKSPACE: return 'workspace';
	}
}

163 164 165 166 167 168 169 170 171 172
interface IZenMode {
	active: boolean;
	transitionedToFullScreen: boolean;
	transitionedToCenteredEditorLayout: boolean;
	transitionDisposeables: IDisposable[];
	wasSideBarVisible: boolean;
	wasPanelVisible: boolean;
}

export class Workbench extends Disposable implements IPartService {
E
Erich Gamma 已提交
173

174
	private static readonly sidebarHiddenStorageKey = 'workbench.sidebar.hidden';
175
	private static readonly menubarVisibilityConfigurationKey = 'window.menuBarVisibility';
176 177 178
	private static readonly sidebarRestoreStorageKey = 'workbench.sidebar.restore';
	private static readonly panelHiddenStorageKey = 'workbench.panel.hidden';
	private static readonly zenModeActiveStorageKey = 'workbench.zenmode.active';
179
	private static readonly centeredEditorLayoutActiveStorageKey = 'workbench.centerededitorlayout.active';
180
	private static readonly panelPositionStorageKey = 'workbench.panel.location';
181
	private static readonly defaultPanelPositionStorageKey = 'workbench.panel.defaultLocation';
182 183 184 185 186
	private static readonly sidebarPositionConfigurationKey = 'workbench.sideBar.location';
	private static readonly statusbarVisibleConfigurationKey = 'workbench.statusBar.visible';
	private static readonly activityBarVisibleConfigurationKey = 'workbench.activityBar.visible';
	private static readonly closeWhenEmptyConfigurationKey = 'window.closeWhenEmpty';
	private static readonly fontAliasingConfigurationKey = 'workbench.fontAliasing';
187

188
	_serviceBrand: any;
189

E
Erich Gamma 已提交
190
	private workbenchParams: WorkbenchParams;
B
Benjamin Pasero 已提交
191
	private workbench: HTMLElement;
E
Erich Gamma 已提交
192 193 194
	private workbenchStarted: boolean;
	private workbenchCreated: boolean;
	private workbenchShutdown: boolean;
195

196 197
	private editorService: EditorService;
	private editorGroupService: IEditorGroupsService;
P
Pine Wu 已提交
198
	private viewletService: IViewletService;
J
Joao Moreno 已提交
199
	private contextViewService: ContextViewService;
200
	private contextKeyService: IContextKeyService;
201
	private keybindingService: IKeybindingService;
202
	private backupFileService: IBackupFileService;
203
	private fileService: IFileService;
204 205 206 207
	private quickInput: QuickInputService;

	private workbenchLayout: WorkbenchLayout;

B
Benjamin Pasero 已提交
208
	private titlebarPart: TitlebarPart;
E
Erich Gamma 已提交
209 210
	private activitybarPart: ActivitybarPart;
	private sidebarPart: SidebarPart;
I
isidor 已提交
211
	private panelPart: PanelPart;
E
Erich Gamma 已提交
212 213 214
	private editorPart: EditorPart;
	private statusbarPart: StatusbarPart;
	private quickOpen: QuickOpenController;
215
	private notificationsCenter: NotificationsCenter;
216
	private notificationsToasts: NotificationsToasts;
217

E
Erich Gamma 已提交
218
	private sideBarHidden: boolean;
219
	private statusBarHidden: boolean;
S
Sanders Lauture 已提交
220
	private activityBarHidden: boolean;
221
	private menubarToggled: boolean;
E
Erich Gamma 已提交
222
	private sideBarPosition: Position;
I
isidor 已提交
223
	private panelPosition: Position;
I
isidor 已提交
224
	private panelHidden: boolean;
S
SteVen Batten 已提交
225
	private menubarVisibility: MenuBarVisibility;
226 227
	private zenMode: IZenMode;
	private fontAliasing: FontAliasingOption;
228
	private hasInitialFilesToOpen: boolean;
229

I
isidor 已提交
230
	private inZenMode: IContextKey<boolean>;
231
	private sideBarVisibleContext: IContextKey<boolean>;
232

B
Benjamin Pasero 已提交
233
	private closeEmptyWindowScheduler: RunOnceScheduler = this._register(new RunOnceScheduler(() => this.onAllEditorsClosed(), 50));
E
Erich Gamma 已提交
234

235
	constructor(
236
		private container: HTMLElement,
J
Joao Moreno 已提交
237
		private configuration: IWindowConfiguration,
238
		serviceCollection: ServiceCollection,
239
		private lifecycleService: LifecycleService,
J
Joao Moreno 已提交
240
		private mainProcessClient: IPCClient,
241
		@IInstantiationService private instantiationService: IInstantiationService,
242
		@IWorkspaceContextService private contextService: IWorkspaceContextService,
243
		@IStorageService private storageService: IStorageService,
244
		@IConfigurationService private configurationService: WorkspaceService,
A
Alex Dima 已提交
245
		@IWorkbenchThemeService private themeService: WorkbenchThemeService,
I
isidor 已提交
246
		@IEnvironmentService private environmentService: IEnvironmentService,
247
		@IWindowService private windowService: IWindowService,
S
SteVen Batten 已提交
248
		@INotificationService private notificationService: NotificationService,
S
SteVen Batten 已提交
249
		@ITelemetryService private telemetryService: TelemetryService
250
	) {
251
		super();
E
Erich Gamma 已提交
252

253
		this.workbenchParams = { configuration, serviceCollection };
E
Erich Gamma 已提交
254

255
		this.hasInitialFilesToOpen =
B
Benjamin Pasero 已提交
256 257 258
			(configuration.filesToCreate && configuration.filesToCreate.length > 0) ||
			(configuration.filesToOpen && configuration.filesToOpen.length > 0) ||
			(configuration.filesToDiff && configuration.filesToDiff.length > 0);
259 260
	}

261
	startup(): TPromise<IWorkbenchStartedInfo> {
262
		this.workbenchStarted = true;
E
Erich Gamma 已提交
263

B
Benjamin Pasero 已提交
264
		// Create Workbench Container
265
		this.createWorkbench();
E
Erich Gamma 已提交
266

267 268
		// Install some global actions
		this.createGlobalActions();
269

270 271
		// Services
		this.initServices();
E
Erich Gamma 已提交
272

273 274
		// Context Keys
		this.handleContextKeys();
J
Joao Moreno 已提交
275

276 277
		// Register Listeners
		this.registerListeners();
E
Erich Gamma 已提交
278

279 280
		// Settings
		this.initSettings();
E
Erich Gamma 已提交
281

282 283
		// Create Workbench and Parts
		this.renderWorkbench();
284

285 286
		// Workbench Layout
		this.createWorkbenchLayout();
B
polish  
Benjamin Pasero 已提交
287

J
Joao Moreno 已提交
288 289
		// Driver
		if (this.environmentService.driverHandle) {
290
			registerWindowDriver(this.mainProcessClient, this.configuration.windowId, this.instantiationService).then(disposable => this._register(disposable));
J
Joao Moreno 已提交
291 292
		}

293
		// Restore Parts
B
Benjamin Pasero 已提交
294 295
		return this.restoreParts();
	}
296

B
Benjamin Pasero 已提交
297
	private createWorkbench(): void {
B
Benjamin Pasero 已提交
298 299 300
		this.workbench = document.createElement('div');
		this.workbench.id = Identifiers.WORKBENCH_CONTAINER;
		DOM.addClasses(this.workbench, 'monaco-workbench', isWindows ? 'windows' : isLinux ? 'linux' : 'mac');
S
SteVen Batten 已提交
301

B
Benjamin Pasero 已提交
302 303 304
		this._register(DOM.addDisposableListener(this.workbench, DOM.EventType.SCROLL, () => {
			this.workbench.scrollTop = 0; // Prevent workbench from scrolling #55456
		}));
305
	}
E
Erich Gamma 已提交
306

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

B
Benjamin Pasero 已提交
310
		// Actions registered here to adjust for developing vs built workbench
311 312 313 314 315
		const registry = Registry.as<IWorkbenchActionRegistry>(Extensions.WorkbenchActions);
		registry.registerWorkbenchAction(new SyncActionDescriptor(ReloadWindowAction, ReloadWindowAction.ID, ReloadWindowAction.LABEL, isDeveloping ? { primary: KeyMod.CtrlCmd | KeyCode.KEY_R } : void 0), 'Reload Window');
		registry.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"));
		registry.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"));
		registry.registerWorkbenchAction(new SyncActionDescriptor(ReloadWindowWithExtensionsDisabledAction, ReloadWindowWithExtensionsDisabledAction.ID, ReloadWindowWithExtensionsDisabledAction.LABEL), 'Reload Window Without Extensions');
316

317
		// Actions for macOS native tabs management (only when enabled)
318
		const windowConfig = this.configurationService.getValue<IWindowConfiguration>();
319
		if (windowConfig && windowConfig.window && windowConfig.window.nativeTabs) {
320
			registry.registerWorkbenchAction(new SyncActionDescriptor(NewWindowTab, NewWindowTab.ID, NewWindowTab.LABEL), 'New Window Tab');
321 322 323 324 325
			registry.registerWorkbenchAction(new SyncActionDescriptor(ShowPreviousWindowTab, ShowPreviousWindowTab.ID, ShowPreviousWindowTab.LABEL), 'Show Previous Window Tab');
			registry.registerWorkbenchAction(new SyncActionDescriptor(ShowNextWindowTab, ShowNextWindowTab.ID, ShowNextWindowTab.LABEL), 'Show Next Window Tab');
			registry.registerWorkbenchAction(new SyncActionDescriptor(MoveWindowTabToNewWindow, MoveWindowTabToNewWindow.ID, MoveWindowTabToNewWindow.LABEL), 'Move Window Tab to New Window');
			registry.registerWorkbenchAction(new SyncActionDescriptor(MergeAllWindowTabs, MergeAllWindowTabs.ID, MergeAllWindowTabs.LABEL), 'Merge All Windows');
			registry.registerWorkbenchAction(new SyncActionDescriptor(ToggleWindowTabsBar, ToggleWindowTabsBar.ID, ToggleWindowTabsBar.LABEL), 'Toggle Window Tabs Bar');
326
		}
327 328
	}

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

E
Erich Gamma 已提交
332
		// Services we contribute
333
		serviceCollection.set(IPartService, this);
E
Erich Gamma 已提交
334

335 336 337
		// Clipboard
		serviceCollection.set(IClipboardService, new ClipboardService());

338 339
		// Status bar
		this.statusbarPart = this.instantiationService.createInstance(StatusbarPart, Identifiers.STATUSBAR_PART);
340
		this._register(toDisposable(() => this.statusbarPart.shutdown()));
341 342
		serviceCollection.set(IStatusbarService, this.statusbarPart);

343 344 345
		// Progress 2
		serviceCollection.set(IProgressService2, new SyncDescriptor(ProgressService2));

346
		// Keybindings
A
Alex Dima 已提交
347
		this.contextKeyService = this.instantiationService.createInstance(ContextKeyService);
348
		serviceCollection.set(IContextKeyService, this.contextKeyService);
349

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

353 354 355
		// List
		serviceCollection.set(IListService, this.instantiationService.createInstance(ListService));

J
Joao Moreno 已提交
356
		// Context view service
B
Benjamin Pasero 已提交
357
		this.contextViewService = this.instantiationService.createInstance(ContextViewService, this.workbench);
J
Joao Moreno 已提交
358 359
		serviceCollection.set(IContextViewService, this.contextViewService);

S
SteVen Batten 已提交
360
		// Use themable context menus when custom titlebar is enabled to match custom menubar
B
Benjamin Pasero 已提交
361
		if (!isMacintosh && this.getCustomTitleBarStyle() === 'custom') {
S
SteVen Batten 已提交
362
			serviceCollection.set(IContextMenuService, new SyncDescriptor(HTMLContextMenuService, null, this.telemetryService, this.notificationService, this.contextViewService));
S
SteVen Batten 已提交
363 364 365
		} else {
			serviceCollection.set(IContextMenuService, new SyncDescriptor(NativeContextMenuService));
		}
366

367 368
		// Menus/Actions
		serviceCollection.set(IMenuService, new SyncDescriptor(MenuService));
369

P
Pine Wu 已提交
370
		// Sidebar part
371
		this.sidebarPart = this.instantiationService.createInstance(SidebarPart, Identifiers.SIDEBAR_PART);
372
		this._register(toDisposable(() => this.sidebarPart.shutdown()));
P
Pine Wu 已提交
373 374 375 376

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

I
isidor 已提交
378
		// Panel service (panel part)
379
		this.panelPart = this.instantiationService.createInstance(PanelPart, Identifiers.PANEL_PART);
380
		this._register(toDisposable(() => this.panelPart.shutdown()));
381
		serviceCollection.set(IPanelService, this.panelPart);
I
isidor 已提交
382

383 384 385
		// views service
		const viewsService = this.instantiationService.createInstance(ViewsService);
		serviceCollection.set(IViewsService, viewsService);
S
Sandeep Somavarapu 已提交
386

E
Erich Gamma 已提交
387
		// Activity service (activitybar part)
388
		this.activitybarPart = this.instantiationService.createInstance(ActivitybarPart, Identifiers.ACTIVITYBAR_PART);
389
		this._register(toDisposable(() => this.activitybarPart.shutdown()));
I
isidor 已提交
390 391
		const activityService = this.instantiationService.createInstance(ActivityService, this.activitybarPart, this.panelPart);
		serviceCollection.set(IActivityService, activityService);
E
Erich Gamma 已提交
392

393 394 395
		// File Service
		this.fileService = this.instantiationService.createInstance(RemoteFileService);
		serviceCollection.set(IFileService, this.fileService);
S
#47154  
Sandeep Somavarapu 已提交
396
		this.configurationService.acquireFileService(this.fileService);
A
Alex Dima 已提交
397
		this.themeService.acquireFileService(this.fileService);
398

399 400
		// Editor and Group services
		const restorePreviousEditorState = !this.hasInitialFilesToOpen;
401
		this.editorPart = this.instantiationService.createInstance(EditorPart, Identifiers.EDITOR_PART, restorePreviousEditorState);
402
		this._register(toDisposable(() => this.editorPart.shutdown()));
B
Benjamin Pasero 已提交
403
		this.editorGroupService = this.editorPart;
404 405 406
		serviceCollection.set(IEditorGroupsService, this.editorPart);
		this.editorService = this.instantiationService.createInstance(EditorService);
		serviceCollection.set(IEditorService, this.editorService);
E
Erich Gamma 已提交
407

408 409
		// Title bar
		this.titlebarPart = this.instantiationService.createInstance(TitlebarPart, Identifiers.TITLEBAR_PART);
410
		this._register(toDisposable(() => this.titlebarPart.shutdown()));
411
		serviceCollection.set(ITitleService, this.titlebarPart);
B
Benjamin Pasero 已提交
412

413
		// History
414
		serviceCollection.set(IHistoryService, new SyncDescriptor(HistoryService));
415

416
		// Backup File Service
B
Benjamin Pasero 已提交
417 418 419 420 421
		if (this.workbenchParams.configuration.backupPath) {
			this.backupFileService = this.instantiationService.createInstance(BackupFileService, this.workbenchParams.configuration.backupPath);
		} else {
			this.backupFileService = new InMemoryBackupFileService();
		}
422
		serviceCollection.set(IBackupFileService, this.backupFileService);
423

424
		// Text File Service
425
		serviceCollection.set(ITextFileService, new SyncDescriptor(TextFileService));
426

427
		// File Decorations
J
Johannes Rieken 已提交
428
		serviceCollection.set(IDecorationsService, new SyncDescriptor(FileDecorationsService));
429

J
Joao Moreno 已提交
430
		// SCM Service
431
		serviceCollection.set(ISCMService, new SyncDescriptor(SCMService));
432

J
Joao Moreno 已提交
433
		// Inactive extension URL handler
J
Joao Moreno 已提交
434
		serviceCollection.set(IExtensionUrlHandler, new SyncDescriptor(ExtensionUrlHandler));
J
Joao Moreno 已提交
435

B
Benjamin Pasero 已提交
436
		// Text Model Resolver Service
437
		serviceCollection.set(ITextModelService, new SyncDescriptor(TextModelResolverService));
B
Benjamin Pasero 已提交
438

439 440 441 442
		// JSON Editing
		const jsonEditingService = this.instantiationService.createInstance(JSONEditingService);
		serviceCollection.set(IJSONEditingService, jsonEditingService);

443 444 445
		// Workspace Editing
		serviceCollection.set(IWorkspaceEditingService, new SyncDescriptor(WorkspaceEditingService));

446 447 448
		// Keybinding Editing
		serviceCollection.set(IKeybindingEditingService, this.instantiationService.createInstance(KeybindingsEditingService));

449
		// Configuration Resolver
B
Benjamin Pasero 已提交
450
		serviceCollection.set(IConfigurationResolverService, new SyncDescriptor(ConfigurationResolverService, process.env));
451

E
Erich Gamma 已提交
452
		// Quick open service (quick open controller)
453
		this.quickOpen = this.instantiationService.createInstance(QuickOpenController);
454
		this._register(toDisposable(() => this.quickOpen.shutdown()));
455
		serviceCollection.set(IQuickOpenService, this.quickOpen);
456

C
Christof Marti 已提交
457 458
		// Quick input service
		this.quickInput = this.instantiationService.createInstance(QuickInputService);
459
		this._register(toDisposable(() => this.quickInput.shutdown()));
C
Christof Marti 已提交
460 461
		serviceCollection.set(IQuickInputService, this.quickInput);

S
Sandeep Somavarapu 已提交
462 463 464
		// PreferencesService
		serviceCollection.set(IPreferencesService, this.instantiationService.createInstance(PreferencesService));

B
polish  
Benjamin Pasero 已提交
465
		// Contributed services
B
Benjamin Pasero 已提交
466
		const contributedServices = getServices();
E
Erich Gamma 已提交
467
		for (let contributedService of contributedServices) {
468
			serviceCollection.set(contributedService.id, contributedService.descriptor);
E
Erich Gamma 已提交
469 470 471
		}

		// Set the some services to registries that have been created eagerly
472
		Registry.as<IActionBarRegistry>(ActionBarExtensions.Actionbar).setInstantiationService(this.instantiationService);
473
		Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench).start(this.instantiationService, this.lifecycleService);
474
		Registry.as<IEditorInputFactoryRegistry>(EditorExtensions.EditorInputFactories).setInstantiationService(this.instantiationService);
475

476
		this.instantiationService.createInstance(DefaultConfigurationExportHelper);
477

S
#47154  
Sandeep Somavarapu 已提交
478
		this.configurationService.acquireInstantiationService(this.getInstantiationService());
E
Erich Gamma 已提交
479 480
	}

481
	//#region event handling
E
Erich Gamma 已提交
482

483
	private registerListeners(): void {
I
isidor 已提交
484

485
		// Listen to visible editor changes
486
		this._register(this.editorService.onDidVisibleEditorsChange(() => this.onDidVisibleEditorsChange()));
B
Benjamin Pasero 已提交
487

488 489 490
		// Listen to editor closing (if we run with --wait)
		const filesToWait = this.workbenchParams.configuration.filesToWait;
		if (filesToWait) {
491
			const resourcesToWaitFor = filesToWait.paths.map(p => p.fileUri);
492
			const waitMarkerFile = URI.file(filesToWait.waitMarkerFilePath);
493
			const listenerDispose = this.editorService.onDidCloseEditor(() => this.onEditorClosed(listenerDispose, resourcesToWaitFor, waitMarkerFile));
I
isidor 已提交
494

495
			this._register(listenerDispose);
496
		}
S
Sanders Lauture 已提交
497

498
		// Configuration changes
499
		this._register(this.configurationService.onDidChangeConfiguration(() => this.onDidUpdateConfiguration()));
I
isidor 已提交
500

501
		// Fullscreen changes
502
		this._register(browser.onDidChangeFullscreen(() => this.onFullscreenChanged()));
503
	}
504

505 506 507 508
	private onFullscreenChanged(): void {
		if (!this.isCreated) {
			return; // we need to be ready
		}
S
SrTobi 已提交
509

510 511 512
		// Apply as CSS class
		const isFullscreen = browser.isFullscreen();
		if (isFullscreen) {
B
Benjamin Pasero 已提交
513
			DOM.addClass(this.workbench, 'fullscreen');
514
		} else {
B
Benjamin Pasero 已提交
515 516
			DOM.removeClass(this.workbench, 'fullscreen');

517 518 519 520
			if (this.zenMode.transitionedToFullScreen && this.zenMode.active) {
				this.toggleZenMode();
			}
		}
E
Erich Gamma 已提交
521

522 523 524 525 526 527
		// 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
		}
528 529
	}

530 531 532 533 534 535 536 537 538 539
	private onMenubarToggled(visible: boolean) {
		if (visible !== this.menubarToggled) {
			this.menubarToggled = visible;

			if (this.menubarVisibility === 'toggle' || (browser.isFullscreen() && this.menubarVisibility === 'default')) {
				this.layout();
			}
		}
	}

540
	private onEditorClosed(listenerDispose: IDisposable, resourcesToWaitFor: URI[], waitMarkerFile: URI): void {
E
Erich Gamma 已提交
541

542 543 544
		// 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.
545
		if (resourcesToWaitFor.every(resource => !this.editorService.isOpen({ resource }))) {
546 547 548
			listenerDispose.dispose();
			this.fileService.del(waitMarkerFile).done(null, errors.onUnexpectedError);
		}
E
Erich Gamma 已提交
549 550
	}

551
	private onDidVisibleEditorsChange(): void {
552
		const visibleEditors = this.editorService.visibleControls;
E
Erich Gamma 已提交
553

554 555 556 557 558 559 560 561 562
		// 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
		// or setting is disabled. Also enabled when running with --wait from the command line.
		if (visibleEditors.length === 0 && this.contextService.getWorkbenchState() === WorkbenchState.EMPTY && !this.environmentService.isExtensionDevelopment) {
			const closeWhenEmpty = this.configurationService.getValue<boolean>(Workbench.closeWhenEmptyConfigurationKey);
			if (closeWhenEmpty || this.environmentService.args.wait) {
				this.closeEmptyWindowScheduler.schedule();
			}
		}
563 564
	}

565
	private onAllEditorsClosed(): void {
566
		const visibleEditors = this.editorService.visibleControls.length;
567 568
		if (visibleEditors === 0) {
			this.windowService.closeWindow();
E
Erich Gamma 已提交
569 570 571
		}
	}

572 573 574 575 576
	private onDidUpdateConfiguration(skipLayout?: boolean): void {
		const newSidebarPositionValue = this.configurationService.getValue<string>(Workbench.sidebarPositionConfigurationKey);
		const newSidebarPosition = (newSidebarPositionValue === 'right') ? Position.RIGHT : Position.LEFT;
		if (newSidebarPosition !== this.getSideBarPosition()) {
			this.setSideBarPosition(newSidebarPosition);
577
		}
E
Erich Gamma 已提交
578

579
		this.setPanelPositionFromStorageOrConfig();
E
Erich Gamma 已提交
580

581 582 583
		const fontAliasing = this.configurationService.getValue<FontAliasingOption>(Workbench.fontAliasingConfigurationKey);
		if (fontAliasing !== this.fontAliasing) {
			this.setFontAliasing(fontAliasing);
584 585
		}

586 587 588 589 590
		if (!this.zenMode.active) {
			const newStatusbarHiddenValue = !this.configurationService.getValue<boolean>(Workbench.statusbarVisibleConfigurationKey);
			if (newStatusbarHiddenValue !== this.statusBarHidden) {
				this.setStatusBarHidden(newStatusbarHiddenValue, skipLayout);
			}
591

592 593 594 595
			const newActivityBarHiddenValue = !this.configurationService.getValue<boolean>(Workbench.activityBarVisibleConfigurationKey);
			if (newActivityBarHiddenValue !== this.activityBarHidden) {
				this.setActivityBarHidden(newActivityBarHiddenValue, skipLayout);
			}
B
Benjamin Pasero 已提交
596
		}
S
SteVen Batten 已提交
597

598
		const newMenubarVisibility = this.configurationService.getValue<MenuBarVisibility>(Workbench.menubarVisibilityConfigurationKey);
S
SteVen Batten 已提交
599
		this.setMenubarVisibility(newMenubarVisibility, skipLayout);
600
	}
B
Benjamin Pasero 已提交
601

602
	//#endregion
B
Benjamin Pasero 已提交
603

604 605
	private handleContextKeys(): void {
		this.inZenMode = InEditorZenModeContext.bindTo(this.contextKeyService);
606

607 608 609 610
		(new RawContextKey<boolean>('isMac', isMacintosh)).bindTo(this.contextKeyService);
		(new RawContextKey<boolean>('isLinux', isLinux)).bindTo(this.contextKeyService);
		(new RawContextKey<boolean>('isWindows', isWindows)).bindTo(this.contextKeyService);

611 612
		const sidebarVisibleContextRaw = new RawContextKey<boolean>('sidebarVisible', false);
		this.sideBarVisibleContext = sidebarVisibleContextRaw.bindTo(this.contextKeyService);
613

614 615
		const editorsVisibleContext = EditorsVisibleContext.bindTo(this.contextKeyService);
		const textCompareEditorVisible = TextCompareEditorVisibleContext.bindTo(this.contextKeyService);
616
		const textCompareEditorActive = TextCompareEditorActiveContext.bindTo(this.contextKeyService);
617 618
		const activeEditorGroupEmpty = ActiveEditorGroupEmptyContext.bindTo(this.contextKeyService);
		const multipleEditorGroups = MultipleEditorGroupsContext.bindTo(this.contextKeyService);
619

620
		const updateEditorContextKeys = () => {
621
			const activeControl = this.editorService.activeControl;
622
			const visibleEditors = this.editorService.visibleControls;
E
Erich Gamma 已提交
623

624
			textCompareEditorActive.set(activeControl && activeControl.getId() === TEXT_DIFF_EDITOR_ID);
625
			textCompareEditorVisible.set(visibleEditors.some(control => control.getId() === TEXT_DIFF_EDITOR_ID));
I
isidor 已提交
626

627 628 629 630
			if (visibleEditors.length > 0) {
				editorsVisibleContext.set(true);
			} else {
				editorsVisibleContext.reset();
631
			}
B
Benjamin Pasero 已提交
632

633
			if (!this.editorService.activeEditor) {
634 635 636
				activeEditorGroupEmpty.set(true);
			} else {
				activeEditorGroupEmpty.reset();
637
			}
638

B
Benjamin Pasero 已提交
639
			if (this.editorGroupService.count > 1) {
640 641 642 643 644
				multipleEditorGroups.set(true);
			} else {
				multipleEditorGroups.reset();
			}
		};
B
Benjamin Pasero 已提交
645

646
		this.editorPart.whenRestored.then(() => updateEditorContextKeys());
647 648
		this._register(this.editorService.onDidActiveEditorChange(() => updateEditorContextKeys()));
		this._register(this.editorService.onDidVisibleEditorsChange(() => updateEditorContextKeys()));
B
Benjamin Pasero 已提交
649 650
		this._register(this.editorGroupService.onDidAddGroup(() => updateEditorContextKeys()));
		this._register(this.editorGroupService.onDidRemoveGroup(() => updateEditorContextKeys()));
651

652 653 654 655 656 657 658 659 660 661
		const inputFocused = InputFocusedContext.bindTo(this.contextKeyService);
		this._register(DOM.addDisposableListener(window, 'focusin', () => {
			inputFocused.set(document.activeElement && (document.activeElement.tagName === 'INPUT' || document.activeElement.tagName === 'TEXTAREA'));
		}, true));

		const workbenchStateRawContext = new RawContextKey<string>('workbenchState', getWorkbenchStateString(this.configurationService.getWorkbenchState()));
		const workbenchStateContext = workbenchStateRawContext.bindTo(this.contextKeyService);
		this._register(this.configurationService.onDidChangeWorkbenchState(() => {
			workbenchStateContext.set(getWorkbenchStateString(this.configurationService.getWorkbenchState()));
		}));
I
isidor 已提交
662

663 664 665 666 667
		const workspaceFolderCountRawContext = new RawContextKey<number>('workspaceFolderCount', this.configurationService.getWorkspace().folders.length);
		const workspaceFolderCountContext = workspaceFolderCountRawContext.bindTo(this.contextKeyService);
		this._register(this.configurationService.onDidChangeWorkspaceFolders(() => {
			workspaceFolderCountContext.set(this.configurationService.getWorkspace().folders.length);
		}));
668

669
		const splitEditorsVerticallyContext = SplitEditorsVertically.bindTo(this.contextKeyService);
S
Sanders Lauture 已提交
670

671 672 673 674
		const updateSplitEditorsVerticallyContext = () => {
			const direction = preferredSideBySideGroupDirection(this.configurationService);
			splitEditorsVerticallyContext.set(direction === GroupDirection.DOWN);
		};
S
Sanders Lauture 已提交
675

676 677 678 679 680
		this._register(this.configurationService.onDidChangeConfiguration(e => {
			if (e.affectsConfiguration('workbench.editor.openSideBySideDirection')) {
				updateSplitEditorsVerticallyContext();
			}
		}));
E
Erich Gamma 已提交
681

682
		updateSplitEditorsVerticallyContext();
683
	}
E
Erich Gamma 已提交
684

685 686
	private restoreParts(): TPromise<IWorkbenchStartedInfo> {
		const restorePromises: Thenable<any>[] = [];
B
Benjamin Pasero 已提交
687

688 689
		// Restore Editorpart
		perf.mark('willRestoreEditors');
690
		restorePromises.push(this.editorPart.whenRestored.then(() => {
691 692
			return this.resolveEditorsToOpen().then(inputs => {
				if (inputs.length) {
693
					return this.editorService.openEditors(inputs);
694
				}
E
Erich Gamma 已提交
695

696 697 698 699 700
				return TPromise.as(void 0);
			});
		}).then(() => {
			perf.mark('didRestoreEditors');
		}));
E
Erich Gamma 已提交
701

702 703 704 705
		// Restore Sidebar
		let viewletIdToRestore: string;
		if (!this.sideBarHidden) {
			this.sideBarVisibleContext.set(true);
706

707 708
			if (this.shouldRestoreLastOpenedViewlet()) {
				viewletIdToRestore = this.storageService.get(SidebarPart.activeViewletSettingsKey, StorageScope.WORKSPACE);
709
			}
710

711 712
			if (!viewletIdToRestore) {
				viewletIdToRestore = this.viewletService.getDefaultViewletId();
713
			}
E
Erich Gamma 已提交
714

715
			perf.mark('willRestoreViewlet');
716 717 718 719 720
			restorePromises.push(this.viewletService.openViewlet(viewletIdToRestore)
				.then(viewlet => viewlet || this.viewletService.openViewlet(this.viewletService.getDefaultViewletId()))
				.then(() => {
					perf.mark('didRestoreViewlet');
				}));
721 722
		}

723 724 725 726
		// Restore Panel
		const panelRegistry = Registry.as<PanelRegistry>(PanelExtensions.Panels);
		const panelId = this.storageService.get(PanelPart.activePanelSettingsKey, StorageScope.WORKSPACE, panelRegistry.getDefaultPanelId());
		if (!this.panelHidden && !!panelId) {
727
			perf.mark('willRestorePanel');
728
			const isPanelToRestoreEnabled = !!this.panelPart.getPanels().filter(p => p.id === panelId).length;
729 730
			const panelIdToRestore = isPanelToRestoreEnabled ? panelId : panelRegistry.getDefaultPanelId();
			restorePromises.push(this.panelPart.openPanel(panelIdToRestore, false).then(() => perf.mark('didRestorePanel')));
I
isidor 已提交
731 732
		}

733
		// Restore Zen Mode if active
I
isidor 已提交
734
		if (this.storageService.getBoolean(Workbench.zenModeActiveStorageKey, StorageScope.WORKSPACE, false)) {
I
isidor 已提交
735
			this.toggleZenMode(true, true);
I
isidor 已提交
736 737
		}

B
Benjamin Pasero 已提交
738
		// Restore Forced Editor Center Mode
739
		if (this.storageService.getBoolean(Workbench.centeredEditorLayoutActiveStorageKey, StorageScope.WORKSPACE, false)) {
I
isidor 已提交
740
			this.centerEditorLayout(true);
S
SrTobi 已提交
741
		}
742

743
		const onRestored = (error?: Error): IWorkbenchStartedInfo => {
B
Benjamin Pasero 已提交
744
			this.workbenchCreated = true;
745

746 747
			if (error) {
				errors.onUnexpectedError(error);
748
			}
I
isidor 已提交
749

750 751 752 753
			return {
				customKeybindingsCount: this.keybindingService.customKeybindingsCount(),
				pinnedViewlets: this.activitybarPart.getPinned(),
				restoredViewlet: viewletIdToRestore,
754
				restoredEditorsCount: this.editorService.visibleEditors.length
755 756
			};
		};
757

758
		return TPromise.join(restorePromises).then(() => onRestored(), error => onRestored(error));
E
Erich Gamma 已提交
759 760
	}

761 762 763
	private shouldRestoreLastOpenedViewlet(): boolean {
		if (!this.environmentService.isBuilt) {
			return true; // always restore sidebar when we are in development mode
E
Erich Gamma 已提交
764 765
		}

766 767 768 769
		const restore = this.storageService.getBoolean(Workbench.sidebarRestoreStorageKey, StorageScope.WORKSPACE);
		if (restore) {
			this.storageService.remove(Workbench.sidebarRestoreStorageKey, StorageScope.WORKSPACE); // only support once
		}
770

771
		return restore;
E
Erich Gamma 已提交
772 773
	}

774
	private resolveEditorsToOpen(): TPromise<IResourceEditor[]> {
775
		const config = this.workbenchParams.configuration;
I
isidor 已提交
776

B
Benjamin Pasero 已提交
777
		// Files to open, diff or create
778
		if (this.hasInitialFilesToOpen) {
I
isidor 已提交
779

B
Benjamin Pasero 已提交
780
			// Files to diff is exclusive
781
			const filesToDiff = this.toInputs(config.filesToDiff, false);
782
			if (filesToDiff && filesToDiff.length === 2) {
783 784 785 786 787
				return TPromise.as([<IResourceDiffInput>{
					leftResource: filesToDiff[0].resource,
					rightResource: filesToDiff[1].resource,
					options: { pinned: true }
				}]);
B
Benjamin Pasero 已提交
788
			}
I
isidor 已提交
789

790 791
			const filesToCreate = this.toInputs(config.filesToCreate, true);
			const filesToOpen = this.toInputs(config.filesToOpen, false);
I
isidor 已提交
792

793 794
			// Otherwise: Open/Create files
			return TPromise.as([...filesToOpen, ...filesToCreate]);
B
Benjamin Pasero 已提交
795
		}
I
isidor 已提交
796

797
		// Empty workbench
798
		else if (this.contextService.getWorkbenchState() === WorkbenchState.EMPTY && this.openUntitledFile()) {
B
Benjamin Pasero 已提交
799
			const isEmpty = this.editorGroupService.count === 1 && this.editorGroupService.activeGroup.count === 0;
800 801
			if (!isEmpty) {
				return TPromise.as([]); // do not open any empty untitled file if we restored editors from previous session
802
			}
B
Benjamin Pasero 已提交
803

804 805 806 807
			return this.backupFileService.hasBackups().then(hasBackups => {
				if (hasBackups) {
					return TPromise.as([]); // do not open any empty untitled file if we have backups to restore
				}
B
Benjamin Pasero 已提交
808

809
				return TPromise.as([<IUntitledResourceInput>{}]);
810
			});
811
		}
812

B
Benjamin Pasero 已提交
813 814
		return TPromise.as([]);
	}
815

816
	private toInputs(paths: IPath[], isNew: boolean): (IResourceInput | IUntitledResourceInput)[] {
B
Benjamin Pasero 已提交
817 818
		if (!paths || !paths.length) {
			return [];
819
		}
I
isidor 已提交
820

B
Benjamin Pasero 已提交
821
		return paths.map(p => {
822
			const resource = p.fileUri;
823 824 825 826 827
			let input: IResourceInput | IUntitledResourceInput;
			if (isNew) {
				input = { filePath: resource.fsPath, options: { pinned: true } } as IUntitledResourceInput;
			} else {
				input = { resource, options: { pinned: true } } as IResourceInput;
828
			}
E
Erich Gamma 已提交
829

830
			if (!isNew && p.lineNumber) {
B
Benjamin Pasero 已提交
831 832 833 834 835
				input.options.selection = {
					startLineNumber: p.lineNumber,
					startColumn: p.columnNumber
				};
			}
836

B
Benjamin Pasero 已提交
837 838
			return input;
		});
839 840
	}

841
	private openUntitledFile() {
842
		const startupEditor = this.configurationService.inspect('workbench.startupEditor');
B
Benjamin Pasero 已提交
843 844

		// Fallback to previous workbench.welcome.enabled setting in case startupEditor is not defined
845
		if (!startupEditor.user && !startupEditor.workspace) {
846 847 848
			const welcomeEnabledValue = this.configurationService.getValue('workbench.welcome.enabled');
			if (typeof welcomeEnabledValue === 'boolean') {
				return !welcomeEnabledValue;
849
			}
850
		}
E
Erich Gamma 已提交
851

852
		return startupEditor.value === 'newUntitledFile';
853
	}
E
Erich Gamma 已提交
854 855

	private initSettings(): void {
856

E
Erich Gamma 已提交
857
		// Sidebar visibility
I
isidor 已提交
858
		this.sideBarHidden = this.storageService.getBoolean(Workbench.sidebarHiddenStorageKey, StorageScope.WORKSPACE, this.contextService.getWorkbenchState() === WorkbenchState.EMPTY);
859

I
isidor 已提交
860
		// Panel part visibility
861
		const panelRegistry = Registry.as<PanelRegistry>(PanelExtensions.Panels);
I
isidor 已提交
862
		this.panelHidden = this.storageService.getBoolean(Workbench.panelHiddenStorageKey, StorageScope.WORKSPACE, true);
863 864
		if (!panelRegistry.getDefaultPanelId()) {
			this.panelHidden = true; // we hide panel part if there is no default panel
865 866
		}

E
Erich Gamma 已提交
867
		// Sidebar position
868
		const sideBarPosition = this.configurationService.getValue<string>(Workbench.sidebarPositionConfigurationKey);
869
		this.sideBarPosition = (sideBarPosition === 'right') ? Position.RIGHT : Position.LEFT;
870

I
isidor 已提交
871
		// Panel position
872
		this.setPanelPositionFromStorageOrConfig();
873

874
		// Menubar visibility
875
		const menuBarVisibility = this.configurationService.getValue<MenuBarVisibility>(Workbench.menubarVisibilityConfigurationKey);
S
SteVen Batten 已提交
876
		this.setMenubarVisibility(menuBarVisibility, true);
877

B
Benjamin Pasero 已提交
878
		// Statusbar visibility
879
		const statusBarVisible = this.configurationService.getValue<string>(Workbench.statusbarVisibleConfigurationKey);
880
		this.statusBarHidden = !statusBarVisible;
881

S
Sanders Lauture 已提交
882
		// Activity bar visibility
883
		const activityBarVisible = this.configurationService.getValue<string>(Workbench.activityBarVisibleConfigurationKey);
S
Sanders Lauture 已提交
884
		this.activityBarHidden = !activityBarVisible;
885

886
		// Font aliasing
887
		this.fontAliasing = this.configurationService.getValue<FontAliasingOption>(Workbench.fontAliasingConfigurationKey);
888

I
isidor 已提交
889 890
		// Zen mode
		this.zenMode = {
I
isidor 已提交
891
			active: false,
892
			transitionedToFullScreen: false,
893
			transitionedToCenteredEditorLayout: false,
894
			wasSideBarVisible: false,
895 896
			wasPanelVisible: false,
			transitionDisposeables: []
I
isidor 已提交
897
		};
E
Erich Gamma 已提交
898 899
	}

900 901 902 903 904
	private setPanelPositionFromStorageOrConfig() {
		const defaultPanelPosition = this.configurationService.getValue<string>(Workbench.defaultPanelPositionStorageKey);
		const panelPosition = this.storageService.get(Workbench.panelPositionStorageKey, StorageScope.WORKSPACE, defaultPanelPosition);
		this.panelPosition = (panelPosition === 'right') ? Position.RIGHT : Position.BOTTOM;
	}
905

906 907
	private getCustomTitleBarStyle(): 'custom' {
		const isDev = !this.environmentService.isBuilt || this.environmentService.isExtensionDevelopment;
B
Benjamin Pasero 已提交
908
		if (isMacintosh && isDev) {
909 910
			return null; // not enabled when developing due to https://github.com/electron/electron/issues/3647
		}
E
Erich Gamma 已提交
911

912 913 914 915 916 917 918 919 920 921
		const windowConfig = this.configurationService.getValue<IWindowSettings>();
		if (windowConfig && windowConfig.window) {
			const useNativeTabs = windowConfig.window.nativeTabs;
			if (useNativeTabs) {
				return null; // native tabs on sierra do not work with custom title style
			}

			const style = windowConfig.window.titleBarStyle;
			if (style === 'custom') {
				return style;
922 923 924
			}
		}

925
		return null;
B
Benjamin Pasero 已提交
926 927
	}

928 929
	private setStatusBarHidden(hidden: boolean, skipLayout?: boolean): void {
		this.statusBarHidden = hidden;
B
Benjamin Pasero 已提交
930

931 932
		// Adjust CSS
		if (hidden) {
B
Benjamin Pasero 已提交
933
			DOM.addClass(this.workbench, 'nostatusbar');
E
Erich Gamma 已提交
934
		} else {
B
Benjamin Pasero 已提交
935
			DOM.removeClass(this.workbench, 'nostatusbar');
E
Erich Gamma 已提交
936 937
		}

938 939 940
		// Layout
		if (!skipLayout) {
			this.workbenchLayout.layout();
941 942 943
		}
	}

944
	private setFontAliasing(aliasing: FontAliasingOption) {
945
		this.fontAliasing = aliasing;
S
Sanders Lauture 已提交
946

B
Benjamin Pasero 已提交
947 948 949 950 951
		// Remove all
		document.body.classList.remove(...fontAliasingValues.map(value => `monaco-font-aliasing-${value}`));

		// Add specific
		if (fontAliasingValues.some(option => option === aliasing)) {
952
			document.body.classList.add(`monaco-font-aliasing-${aliasing}`);
S
Sanders Lauture 已提交
953
		}
954 955
	}

E
Erich Gamma 已提交
956
	private createWorkbenchLayout(): void {
957 958
		this.workbenchLayout = this.instantiationService.createInstance(
			WorkbenchLayout,
959
			this.container,
B
Benjamin Pasero 已提交
960
			this.workbench,
I
isidor 已提交
961
			{
962 963 964 965 966 967
				titlebar: this.titlebarPart,
				activitybar: this.activitybarPart,
				editor: this.editorPart,
				sidebar: this.sidebarPart,
				panel: this.panelPart,
				statusbar: this.statusbarPart,
I
isidor 已提交
968
			},
969 970 971 972
			this.quickOpen,
			this.quickInput,
			this.notificationsCenter,
			this.notificationsToasts
E
Erich Gamma 已提交
973 974 975 976 977 978 979
		);
	}

	private renderWorkbench(): void {

		// Apply sidebar state as CSS class
		if (this.sideBarHidden) {
B
Benjamin Pasero 已提交
980
			DOM.addClass(this.workbench, 'nosidebar');
E
Erich Gamma 已提交
981
		}
B
Benjamin Pasero 已提交
982

983
		if (this.panelHidden) {
B
Benjamin Pasero 已提交
984
			DOM.addClass(this.workbench, 'nopanel');
985
		}
B
Benjamin Pasero 已提交
986

987
		if (this.statusBarHidden) {
B
Benjamin Pasero 已提交
988
			DOM.addClass(this.workbench, 'nostatusbar');
989
		}
E
Erich Gamma 已提交
990

B
Benjamin Pasero 已提交
991
		// Apply font aliasing
992 993
		this.setFontAliasing(this.fontAliasing);

994 995
		// Apply fullscreen state
		if (browser.isFullscreen()) {
B
Benjamin Pasero 已提交
996
			DOM.addClass(this.workbench, 'fullscreen');
B
Benjamin Pasero 已提交
997 998
		}

E
Erich Gamma 已提交
999
		// Create Parts
B
Benjamin Pasero 已提交
1000
		this.createTitlebarPart();
E
Erich Gamma 已提交
1001 1002 1003
		this.createActivityBarPart();
		this.createSidebarPart();
		this.createEditorPart();
1004
		this.createPanelPart();
E
Erich Gamma 已提交
1005 1006
		this.createStatusbarPart();

1007 1008
		// Notification Handlers
		this.createNotificationsHandlers();
1009

1010 1011 1012 1013 1014 1015

		// Menubar visibility changes
		if ((isWindows || isLinux) && this.getCustomTitleBarStyle() === 'custom') {
			this.titlebarPart.onMenubarVisibilityChange()(e => this.onMenubarToggled(e));
		}

E
Erich Gamma 已提交
1016
		// Add Workbench to DOM
B
Benjamin Pasero 已提交
1017
		this.container.appendChild(this.workbench);
E
Erich Gamma 已提交
1018 1019
	}

B
Benjamin Pasero 已提交
1020
	private createTitlebarPart(): void {
B
Benjamin Pasero 已提交
1021
		const titlebarContainer = this.createPart(Identifiers.TITLEBAR_PART, ['part', 'titlebar'], 'contentinfo');
B
Benjamin Pasero 已提交
1022

B
Benjamin Pasero 已提交
1023
		this.titlebarPart.create(titlebarContainer);
B
Benjamin Pasero 已提交
1024 1025
	}

E
Erich Gamma 已提交
1026
	private createActivityBarPart(): void {
B
Benjamin Pasero 已提交
1027
		const activitybarPartContainer = this.createPart(Identifiers.ACTIVITYBAR_PART, ['part', 'activitybar', this.sideBarPosition === Position.LEFT ? 'left' : 'right'], 'navigation');
E
Erich Gamma 已提交
1028

B
Benjamin Pasero 已提交
1029
		this.activitybarPart.create(activitybarPartContainer);
E
Erich Gamma 已提交
1030 1031 1032
	}

	private createSidebarPart(): void {
B
Benjamin Pasero 已提交
1033
		const sidebarPartContainer = this.createPart(Identifiers.SIDEBAR_PART, ['part', 'sidebar', this.sideBarPosition === Position.LEFT ? 'left' : 'right'], 'complementary');
E
Erich Gamma 已提交
1034

B
Benjamin Pasero 已提交
1035
		this.sidebarPart.create(sidebarPartContainer);
E
Erich Gamma 已提交
1036 1037
	}

I
isidor 已提交
1038
	private createPanelPart(): void {
B
Benjamin Pasero 已提交
1039
		const panelPartContainer = this.createPart(Identifiers.PANEL_PART, ['part', 'panel', this.panelPosition === Position.BOTTOM ? 'bottom' : 'right'], 'complementary');
I
isidor 已提交
1040

B
Benjamin Pasero 已提交
1041
		this.panelPart.create(panelPartContainer);
I
isidor 已提交
1042 1043
	}

E
Erich Gamma 已提交
1044
	private createEditorPart(): void {
B
Benjamin Pasero 已提交
1045
		const editorContainer = this.createPart(Identifiers.EDITOR_PART, ['part', 'editor'], 'main');
E
Erich Gamma 已提交
1046

B
Benjamin Pasero 已提交
1047
		this.editorPart.create(editorContainer);
E
Erich Gamma 已提交
1048 1049 1050
	}

	private createStatusbarPart(): void {
B
Benjamin Pasero 已提交
1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062
		const statusbarContainer = this.createPart(Identifiers.STATUSBAR_PART, ['part', 'statusbar'], 'contentinfo');

		this.statusbarPart.create(statusbarContainer);
	}

	private createPart(id: string, classes: string[], role: string): HTMLElement {
		const part = document.createElement('div');
		classes.forEach(clazz => DOM.addClass(part, clazz));
		part.id = id;
		part.setAttribute('role', role);

		this.workbench.appendChild(part);
E
Erich Gamma 已提交
1063

B
Benjamin Pasero 已提交
1064
		return part;
E
Erich Gamma 已提交
1065 1066
	}

1067 1068
	private createNotificationsHandlers(): void {

1069
		// Notifications Center
B
Benjamin Pasero 已提交
1070
		this.notificationsCenter = this._register(this.instantiationService.createInstance(NotificationsCenter, this.workbench, this.notificationService.model));
1071

1072
		// Notifications Toasts
B
Benjamin Pasero 已提交
1073
		this.notificationsToasts = this._register(this.instantiationService.createInstance(NotificationsToasts, this.workbench, this.notificationService.model));
1074

1075
		// Notifications Alerts
1076
		this._register(this.instantiationService.createInstance(NotificationsAlerts, this.notificationService.model));
1077 1078 1079 1080

		// Notifications Status
		const notificationsStatus = this.instantiationService.createInstance(NotificationsStatus, this.notificationService.model);

1081
		// Eventing
1082
		this._register(this.notificationsCenter.onDidChangeVisibility(() => {
1083 1084 1085 1086 1087 1088 1089 1090

			// Update status
			notificationsStatus.update(this.notificationsCenter.isVisible);

			// Update toasts
			this.notificationsToasts.update(this.notificationsCenter.isVisible);
		}));

1091
		// Register Commands
1092
		registerNotificationCommands(this.notificationsCenter, this.notificationsToasts);
1093 1094
	}

1095
	getInstantiationService(): IInstantiationService {
E
Erich Gamma 已提交
1096 1097 1098
		return this.instantiationService;
	}

1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123
	dispose(reason = ShutdownReason.QUIT): void {
		super.dispose();

		// Restore sidebar if we are being shutdown as a matter of a reload
		if (reason === ShutdownReason.RELOAD) {
			this.storageService.store(Workbench.sidebarRestoreStorageKey, 'true', StorageScope.WORKSPACE);
		}

		// Preserve zen mode only on reload. Real quit gets out of zen mode so novice users do not get stuck in zen mode.
		const zenConfig = this.configurationService.getValue<IZenModeSettings>('zenMode');
		const restoreZenMode = this.zenMode.active && (zenConfig.restore || reason === ShutdownReason.RELOAD);
		if (restoreZenMode) {
			this.storageService.store(Workbench.zenModeActiveStorageKey, true, StorageScope.WORKSPACE);
		} else {
			if (this.zenMode.active) {
				this.toggleZenMode(true);
			}
			this.storageService.remove(Workbench.zenModeActiveStorageKey, StorageScope.WORKSPACE);
		}

		this.workbenchShutdown = true;
	}

	//#region IPartService

B
Benjamin Pasero 已提交
1124
	private _onTitleBarVisibilityChange: Emitter<void> = this._register(new Emitter<void>());
1125
	get onTitleBarVisibilityChange(): Event<void> { return this._onTitleBarVisibilityChange.event; }
1126

1127
	get onEditorLayout(): Event<IDimension> { return this.editorPart.onDidLayout; }
1128

1129
	isCreated(): boolean {
1130
		return !!(this.workbenchCreated && this.workbenchStarted);
1131
	}
1132

1133 1134 1135 1136 1137
	hasFocus(part: Parts): boolean {
		const activeElement = document.activeElement;
		if (!activeElement) {
			return false;
		}
1138

1139 1140 1141
		const container = this.getContainer(part);
		return DOM.isAncestor(activeElement, container);
	}
1142

1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164
	getContainer(part: Parts): HTMLElement {
		let container: HTMLElement = null;
		switch (part) {
			case Parts.TITLEBAR_PART:
				container = this.titlebarPart.getContainer();
				break;
			case Parts.ACTIVITYBAR_PART:
				container = this.activitybarPart.getContainer();
				break;
			case Parts.SIDEBAR_PART:
				container = this.sidebarPart.getContainer();
				break;
			case Parts.PANEL_PART:
				container = this.panelPart.getContainer();
				break;
			case Parts.EDITOR_PART:
				container = this.editorPart.getContainer();
				break;
			case Parts.STATUSBAR_PART:
				container = this.statusbarPart.getContainer();
				break;
		}
1165

1166 1167
		return container;
	}
1168

1169 1170 1171
	isVisible(part: Parts): boolean {
		switch (part) {
			case Parts.TITLEBAR_PART:
1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184
				if (this.getCustomTitleBarStyle() !== 'custom') {
					return false;
				} else if (!browser.isFullscreen()) {
					return true;
				} else if (isMacintosh) {
					return false;
				} else if (this.menubarVisibility === 'visible') {
					return true;
				} else if (this.menubarVisibility === 'toggle' || this.menubarVisibility === 'default') {
					return this.menubarToggled;
				}

				return false;
1185 1186 1187 1188 1189 1190 1191 1192
			case Parts.SIDEBAR_PART:
				return !this.sideBarHidden;
			case Parts.PANEL_PART:
				return !this.panelHidden;
			case Parts.STATUSBAR_PART:
				return !this.statusBarHidden;
			case Parts.ACTIVITYBAR_PART:
				return !this.activityBarHidden;
E
Erich Gamma 已提交
1193
		}
1194

1195
		return true; // any other part cannot be hidden
E
Erich Gamma 已提交
1196 1197
	}

1198 1199 1200
	getTitleBarOffset(): number {
		let offset = 0;
		if (this.isVisible(Parts.TITLEBAR_PART)) {
S
SteVen Batten 已提交
1201
			offset = this.workbenchLayout.partLayoutInfo.titlebar.height;
1202 1203 1204
			if (isMacintosh || this.menubarVisibility === 'hidden') {
				offset /= browser.getZoomFactor();
			}
E
Erich Gamma 已提交
1205
		}
1206 1207

		return offset;
E
Erich Gamma 已提交
1208
	}
1209

1210
	getWorkbenchElementId(): string {
1211 1212
		return Identifiers.WORKBENCH_CONTAINER;
	}
1213

I
isidor 已提交
1214
	toggleZenMode(skipLayout?: boolean, restoring = false): void {
I
isidor 已提交
1215
		this.zenMode.active = !this.zenMode.active;
1216
		this.zenMode.transitionDisposeables = dispose(this.zenMode.transitionDisposeables);
1217

1218 1219
		// 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 (same goes for the centered editor layout)
1220
		let toggleFullScreen = false;
1221 1222

		// Zen Mode Active
I
isidor 已提交
1223
		if (this.zenMode.active) {
1224
			const config = this.configurationService.getValue<IZenModeSettings>('zenMode');
1225

I
isidor 已提交
1226
			toggleFullScreen = !browser.isFullscreen() && config.fullScreen;
I
isidor 已提交
1227
			this.zenMode.transitionedToFullScreen = restoring ? config.fullScreen : toggleFullScreen;
1228
			this.zenMode.transitionedToCenteredEditorLayout = !this.isEditorLayoutCentered() && config.centerLayout;
1229 1230
			this.zenMode.wasSideBarVisible = this.isVisible(Parts.SIDEBAR_PART);
			this.zenMode.wasPanelVisible = this.isVisible(Parts.PANEL_PART);
1231

1232 1233
			this.setPanelHidden(true, true).done(void 0, errors.onUnexpectedError);
			this.setSideBarHidden(true, true).done(void 0, errors.onUnexpectedError);
I
isidor 已提交
1234

1235 1236 1237
			if (config.hideActivityBar) {
				this.setActivityBarHidden(true, true);
			}
1238

I
isidor 已提交
1239
			if (config.hideStatusBar) {
I
isidor 已提交
1240 1241
				this.setStatusBarHidden(true, true);
			}
1242

1243 1244
			if (config.hideTabs && this.editorPart.partOptions.showTabs) {
				this.zenMode.transitionDisposeables.push(this.editorPart.enforcePartOptions({ showTabs: false }));
I
isidor 已提交
1245
			}
1246 1247 1248 1249

			if (config.centerLayout) {
				this.centerEditorLayout(true, true);
			}
1250 1251 1252 1253
		}

		// Zen Mode Inactive
		else {
1254
			if (this.zenMode.wasPanelVisible) {
1255
				this.setPanelHidden(false, true).done(void 0, errors.onUnexpectedError);
1256
			}
1257

1258
			if (this.zenMode.wasSideBarVisible) {
1259
				this.setSideBarHidden(false, true).done(void 0, errors.onUnexpectedError);
1260
			}
1261

1262 1263 1264
			if (this.zenMode.transitionedToCenteredEditorLayout) {
				this.centerEditorLayout(false, true);
			}
1265

1266 1267
			// Status bar and activity bar visibility come from settings -> update their visibility.
			this.onDidUpdateConfiguration(true);
1268

B
Benjamin Pasero 已提交
1269
			this.editorGroupService.activeGroup.focus();
1270

1271
			toggleFullScreen = this.zenMode.transitionedToFullScreen && browser.isFullscreen();
I
isidor 已提交
1272
		}
1273

1274
		this.inZenMode.set(this.zenMode.active);
I
isidor 已提交
1275

I
isidor 已提交
1276
		if (!skipLayout) {
1277
			this.layout();
I
isidor 已提交
1278
		}
1279

1280
		if (toggleFullScreen) {
1281
			this.windowService.toggleFullScreen().done(void 0, errors.onUnexpectedError);
1282
		}
I
isidor 已提交
1283 1284
	}

1285
	layout(options?: ILayoutOptions): void {
J
Joao Moreno 已提交
1286 1287
		this.contextViewService.layout();

1288 1289 1290 1291 1292
		if (this.workbenchStarted && !this.workbenchShutdown) {
			this.workbenchLayout.layout(options);
		}
	}

1293
	isEditorLayoutCentered(): boolean {
I
isidor 已提交
1294
		return this.editorPart.isLayoutCentered();
S
SrTobi 已提交
1295 1296
	}

1297
	centerEditorLayout(active: boolean, skipLayout?: boolean): void {
I
isidor 已提交
1298
		this.storageService.store(Workbench.centeredEditorLayoutActiveStorageKey, active, StorageScope.WORKSPACE);
B
Benjamin Pasero 已提交
1299

1300
		// Enter Centered Editor Layout
I
isidor 已提交
1301
		this.editorPart.centerLayout(active);
1302

1303 1304 1305
		if (!skipLayout) {
			this.layout();
		}
S
SrTobi 已提交
1306 1307
	}

1308
	resizePart(part: Parts, sizeChange: number): void {
1309 1310 1311 1312 1313 1314 1315
		switch (part) {
			case Parts.SIDEBAR_PART:
			case Parts.PANEL_PART:
			case Parts.EDITOR_PART:
				this.workbenchLayout.resizePart(part, sizeChange);
				break;
			default:
B
Benjamin Pasero 已提交
1316
				return; // Cannot resize other parts
1317 1318 1319
		}
	}

1320 1321
	setActivityBarHidden(hidden: boolean, skipLayout?: boolean): void {
		this.activityBarHidden = hidden;
1322

1323 1324 1325
		// Layout
		if (!skipLayout) {
			this.workbenchLayout.layout();
1326
		}
1327
	}
1328

1329 1330 1331 1332 1333 1334
	setSideBarHidden(hidden: boolean, skipLayout?: boolean): TPromise<void> {
		this.sideBarHidden = hidden;
		this.sideBarVisibleContext.set(!hidden);

		// Adjust CSS
		if (hidden) {
B
Benjamin Pasero 已提交
1335
			DOM.addClass(this.workbench, 'nosidebar');
1336
		} else {
B
Benjamin Pasero 已提交
1337
			DOM.removeClass(this.workbench, 'nosidebar');
1338 1339
		}

1340 1341 1342 1343 1344 1345 1346 1347 1348
		// If sidebar becomes hidden, also hide the current active Viewlet if any
		let promise = TPromise.wrap<any>(null);
		if (hidden && this.sidebarPart.getActiveViewlet()) {
			promise = this.sidebarPart.hideActiveViewlet().then(() => {
				const activePanel = this.panelPart.getActivePanel();

				// Pass Focus to Editor or Panel if Sidebar is now hidden
				if (this.hasFocus(Parts.PANEL_PART) && activePanel) {
					activePanel.focus();
B
Benjamin Pasero 已提交
1349 1350
				} else {
					this.editorGroupService.activeGroup.focus();
1351 1352 1353 1354 1355 1356 1357 1358
				}
			});
		}

		// If sidebar becomes visible, show last active Viewlet or default viewlet
		else if (!hidden && !this.sidebarPart.getActiveViewlet()) {
			const viewletToOpen = this.sidebarPart.getLastActiveViewletId();
			if (viewletToOpen) {
1359 1360
				promise = this.viewletService.openViewlet(viewletToOpen, true)
					.then(viewlet => viewlet || this.viewletService.openViewlet(this.viewletService.getDefaultViewletId(), true));
1361
			}
1362 1363
		}

1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378
		return promise.then(() => {

			// Remember in settings
			const defaultHidden = this.contextService.getWorkbenchState() === WorkbenchState.EMPTY;
			if (hidden !== defaultHidden) {
				this.storageService.store(Workbench.sidebarHiddenStorageKey, hidden ? 'true' : 'false', StorageScope.WORKSPACE);
			} else {
				this.storageService.remove(Workbench.sidebarHiddenStorageKey, StorageScope.WORKSPACE);
			}

			// Layout
			if (!skipLayout) {
				this.workbenchLayout.layout();
			}
		});
1379
	}
1380 1381 1382 1383 1384 1385

	setPanelHidden(hidden: boolean, skipLayout?: boolean): TPromise<void> {
		this.panelHidden = hidden;

		// Adjust CSS
		if (hidden) {
B
Benjamin Pasero 已提交
1386
			DOM.addClass(this.workbench, 'nopanel');
1387
		} else {
B
Benjamin Pasero 已提交
1388
			DOM.removeClass(this.workbench, 'nopanel');
1389 1390 1391 1392 1393 1394
		}

		// If panel part becomes hidden, also hide the current active panel if any
		let promise = TPromise.wrap<any>(null);
		if (hidden && this.panelPart.getActivePanel()) {
			promise = this.panelPart.hideActivePanel().then(() => {
B
Benjamin Pasero 已提交
1395
				this.editorGroupService.activeGroup.focus(); // Pass focus to editor group if panel part is now hidden
1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457
			});
		}

		// If panel part becomes visible, show last active panel or default panel
		else if (!hidden && !this.panelPart.getActivePanel()) {
			const panelToOpen = this.panelPart.getLastActivePanelId();
			if (panelToOpen) {
				promise = this.panelPart.openPanel(panelToOpen, true);
			}
		}

		return promise.then(() => {

			// Remember in settings
			if (!hidden) {
				this.storageService.store(Workbench.panelHiddenStorageKey, 'false', StorageScope.WORKSPACE);
			} else {
				this.storageService.remove(Workbench.panelHiddenStorageKey, StorageScope.WORKSPACE);
			}

			// Layout
			if (!skipLayout) {
				this.workbenchLayout.layout();
			}
		});
	}

	toggleMaximizedPanel(): void {
		this.workbenchLayout.layout({ toggleMaximizedPanel: true, source: Parts.PANEL_PART });
	}

	isPanelMaximized(): boolean {
		return this.workbenchLayout.isPanelMaximized();
	}

	getSideBarPosition(): Position {
		return this.sideBarPosition;
	}

	setSideBarPosition(position: Position): void {
		if (this.sideBarHidden) {
			this.setSideBarHidden(false, true /* Skip Layout */).done(void 0, errors.onUnexpectedError);
		}

		const newPositionValue = (position === Position.LEFT) ? 'left' : 'right';
		const oldPositionValue = (this.sideBarPosition === Position.LEFT) ? 'left' : 'right';
		this.sideBarPosition = position;

		// Adjust CSS
		DOM.removeClass(this.activitybarPart.getContainer(), oldPositionValue);
		DOM.removeClass(this.sidebarPart.getContainer(), oldPositionValue);
		DOM.addClass(this.activitybarPart.getContainer(), newPositionValue);
		DOM.addClass(this.sidebarPart.getContainer(), newPositionValue);

		// Update Styles
		this.activitybarPart.updateStyles();
		this.sidebarPart.updateStyles();

		// Layout
		this.workbenchLayout.layout();
	}

S
SteVen Batten 已提交
1458
	setMenubarVisibility(visibility: MenuBarVisibility, skipLayout: boolean): void {
S
SteVen Batten 已提交
1459 1460
		if (this.menubarVisibility !== visibility) {
			this.menubarVisibility = visibility;
1461

S
SteVen Batten 已提交
1462 1463 1464
			if (!skipLayout) {
				this.workbenchLayout.layout();
			}
1465 1466 1467
		}
	}

S
SteVen Batten 已提交
1468 1469 1470 1471
	getMenubarVisibility(): MenuBarVisibility {
		return this.menubarVisibility;
	}

1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492
	getPanelPosition(): Position {
		return this.panelPosition;
	}

	setPanelPosition(position: Position): TPromise<void> {
		return (this.panelHidden ? this.setPanelHidden(false, true /* Skip Layout */) : TPromise.as(undefined)).then(() => {
			const newPositionValue = (position === Position.BOTTOM) ? 'bottom' : 'right';
			const oldPositionValue = (this.panelPosition === Position.BOTTOM) ? 'bottom' : 'right';
			this.panelPosition = position;
			this.storageService.store(Workbench.panelPositionStorageKey, Position[this.panelPosition].toLowerCase(), StorageScope.WORKSPACE);

			// Adjust CSS
			DOM.removeClass(this.panelPart.getContainer(), oldPositionValue);
			DOM.addClass(this.panelPart.getContainer(), newPositionValue);

			// Update Styles
			this.panelPart.updateStyles();

			// Layout
			this.workbenchLayout.layout();
		});
1493
	}
1494 1495

	//#endregion
I
isidor 已提交
1496
}