workbench.ts 60.1 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, ActiveEditorContext } 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';
A
Alex Dima 已提交
40
import { Position, Parts, IPartService, ILayoutOptions, IDimension, PositionToString } 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';
94
import { URI } from 'vs/base/common/uri';
J
Joao Moreno 已提交
95
import { IListService, ListService } from 'vs/platform/list/browser/listService';
96
import { InputFocusedContext, IsMacContext, IsLinuxContext, IsWindowsContext, FileDialogContext } 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/workbench/services/extensions/electron-browser/inactiveExtensionUrlHandler';
S
SteVen Batten 已提交
114
import { ContextViewService } from 'vs/platform/contextview/browser/contextViewService';
A
Alex Dima 已提交
115 116
import { WorkbenchThemeService } from 'vs/workbench/services/themes/electron-browser/workbenchThemeService';
import { IWorkbenchThemeService } from 'vs/workbench/services/themes/common/workbenchThemeService';
I
isidor 已提交
117
import { LabelService, ILabelService } from 'vs/platform/label/common/label';
118

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

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

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

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

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

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

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

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

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

173
	private static readonly sidebarHiddenStorageKey = 'workbench.sidebar.hidden';
174
	private static readonly menubarVisibilityConfigurationKey = 'window.menuBarVisibility';
175 176 177
	private static readonly sidebarRestoreStorageKey = 'workbench.sidebar.restore';
	private static readonly panelHiddenStorageKey = 'workbench.panel.hidden';
	private static readonly zenModeActiveStorageKey = 'workbench.zenmode.active';
178
	private static readonly centeredEditorLayoutActiveStorageKey = 'workbench.centerededitorlayout.active';
179
	private static readonly panelPositionStorageKey = 'workbench.panel.location';
180
	private static readonly defaultPanelPositionStorageKey = 'workbench.panel.defaultLocation';
181 182 183 184 185
	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';
186

187
	_serviceBrand: any;
188

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

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

	private workbenchLayout: WorkbenchLayout;

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

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

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

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

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

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

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

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

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

265 266
		// Install some global actions
		this.createGlobalActions();
267

268 269
		// Services
		this.initServices();
E
Erich Gamma 已提交
270

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

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

277 278
		// Settings
		this.initSettings();
E
Erich Gamma 已提交
279

280 281
		// Create Workbench and Parts
		this.renderWorkbench();
282

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

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

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

B
Benjamin Pasero 已提交
295
	private createWorkbench(): void {
B
Benjamin Pasero 已提交
296 297 298
		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 已提交
299

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

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

B
Benjamin Pasero 已提交
308
		// Actions registered here to adjust for developing vs built workbench
309 310 311 312 313
		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');
314

315
		// Actions for macOS native tabs management (only when enabled)
316
		const windowConfig = this.configurationService.getValue<IWindowConfiguration>();
317
		if (windowConfig && windowConfig.window && windowConfig.window.nativeTabs) {
318
			registry.registerWorkbenchAction(new SyncActionDescriptor(NewWindowTab, NewWindowTab.ID, NewWindowTab.LABEL), 'New Window Tab');
319 320 321 322 323
			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');
324
		}
325 326
	}

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

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

333 334 335
		// Clipboard
		serviceCollection.set(IClipboardService, new ClipboardService());

I
isidor 已提交
336
		// Uri Display
I
isidor 已提交
337 338
		const labelService = new LabelService(this.environmentService, this.contextService);
		serviceCollection.set(ILabelService, labelService);
I
isidor 已提交
339

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

345 346 347
		// Progress 2
		serviceCollection.set(IProgressService2, new SyncDescriptor(ProgressService2));

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

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

355 356 357
		// List
		serviceCollection.set(IListService, this.instantiationService.createInstance(ListService));

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

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

369 370
		// Menus/Actions
		serviceCollection.set(IMenuService, new SyncDescriptor(MenuService));
371

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

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

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

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

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

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

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

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

415
		// History
416
		serviceCollection.set(IHistoryService, new SyncDescriptor(HistoryService));
417

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

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

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

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

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

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

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

445 446 447
		// Workspace Editing
		serviceCollection.set(IWorkspaceEditingService, new SyncDescriptor(WorkspaceEditingService));

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

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

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

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

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

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

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

478
		this.instantiationService.createInstance(DefaultConfigurationExportHelper);
479

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

483
	//#region event handling
E
Erich Gamma 已提交
484

485
	private registerListeners(): void {
I
isidor 已提交
486

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

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

497
			this._register(listenerDispose);
498
		}
S
Sanders Lauture 已提交
499

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

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

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

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

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

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

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

			if (this.menubarVisibility === 'toggle' || (browser.isFullscreen() && this.menubarVisibility === 'default')) {
S
SteVen Batten 已提交
537 538 539 540
				if (browser.isFullscreen() && this.menubarVisibility === 'default') {
					this._onTitleBarVisibilityChange.fire();
				}

541 542 543 544 545
				this.layout();
			}
		}
	}

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

548 549 550
		// 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.
551
		if (resourcesToWaitFor.every(resource => !this.editorService.isOpen({ resource }))) {
552
			listenerDispose.dispose();
553
			this.fileService.del(waitMarkerFile);
554
		}
E
Erich Gamma 已提交
555 556
	}

557
	private onDidVisibleEditorsChange(): void {
558
		const visibleEditors = this.editorService.visibleControls;
E
Erich Gamma 已提交
559

560 561 562 563 564 565 566 567 568
		// 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();
			}
		}
569 570
	}

571
	private onAllEditorsClosed(): void {
572
		const visibleEditors = this.editorService.visibleControls.length;
573 574
		if (visibleEditors === 0) {
			this.windowService.closeWindow();
E
Erich Gamma 已提交
575 576 577
		}
	}

578 579 580 581 582
	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);
583
		}
E
Erich Gamma 已提交
584

585
		this.setPanelPositionFromStorageOrConfig();
E
Erich Gamma 已提交
586

587 588 589
		const fontAliasing = this.configurationService.getValue<FontAliasingOption>(Workbench.fontAliasingConfigurationKey);
		if (fontAliasing !== this.fontAliasing) {
			this.setFontAliasing(fontAliasing);
590 591
		}

592 593 594 595 596
		if (!this.zenMode.active) {
			const newStatusbarHiddenValue = !this.configurationService.getValue<boolean>(Workbench.statusbarVisibleConfigurationKey);
			if (newStatusbarHiddenValue !== this.statusBarHidden) {
				this.setStatusBarHidden(newStatusbarHiddenValue, skipLayout);
			}
597

598 599 600 601
			const newActivityBarHiddenValue = !this.configurationService.getValue<boolean>(Workbench.activityBarVisibleConfigurationKey);
			if (newActivityBarHiddenValue !== this.activityBarHidden) {
				this.setActivityBarHidden(newActivityBarHiddenValue, skipLayout);
			}
B
Benjamin Pasero 已提交
602
		}
S
SteVen Batten 已提交
603

604
		const newMenubarVisibility = this.configurationService.getValue<MenuBarVisibility>(Workbench.menubarVisibilityConfigurationKey);
S
SteVen Batten 已提交
605
		this.setMenubarVisibility(newMenubarVisibility, skipLayout);
606
	}
B
Benjamin Pasero 已提交
607

608
	//#endregion
B
Benjamin Pasero 已提交
609

610 611
	private handleContextKeys(): void {
		this.inZenMode = InEditorZenModeContext.bindTo(this.contextKeyService);
612

I
isidor 已提交
613 614 615
		IsMacContext.bindTo(this.contextKeyService);
		IsLinuxContext.bindTo(this.contextKeyService);
		IsWindowsContext.bindTo(this.contextKeyService);
616
		FileDialogContext.bindTo(this.contextKeyService);
617

618 619
		const sidebarVisibleContextRaw = new RawContextKey<boolean>('sidebarVisible', false);
		this.sideBarVisibleContext = sidebarVisibleContextRaw.bindTo(this.contextKeyService);
620

621
		const activeEditorContext = ActiveEditorContext.bindTo(this.contextKeyService);
622 623
		const editorsVisibleContext = EditorsVisibleContext.bindTo(this.contextKeyService);
		const textCompareEditorVisible = TextCompareEditorVisibleContext.bindTo(this.contextKeyService);
624
		const textCompareEditorActive = TextCompareEditorActiveContext.bindTo(this.contextKeyService);
625 626
		const activeEditorGroupEmpty = ActiveEditorGroupEmptyContext.bindTo(this.contextKeyService);
		const multipleEditorGroups = MultipleEditorGroupsContext.bindTo(this.contextKeyService);
627

628
		const updateEditorContextKeys = () => {
629
			const activeControl = this.editorService.activeControl;
630
			const visibleEditors = this.editorService.visibleControls;
E
Erich Gamma 已提交
631

632
			textCompareEditorActive.set(activeControl && activeControl.getId() === TEXT_DIFF_EDITOR_ID);
633
			textCompareEditorVisible.set(visibleEditors.some(control => control.getId() === TEXT_DIFF_EDITOR_ID));
I
isidor 已提交
634

635 636 637 638
			if (visibleEditors.length > 0) {
				editorsVisibleContext.set(true);
			} else {
				editorsVisibleContext.reset();
639
			}
B
Benjamin Pasero 已提交
640

641
			if (!this.editorService.activeEditor) {
642 643 644
				activeEditorGroupEmpty.set(true);
			} else {
				activeEditorGroupEmpty.reset();
645
			}
646

B
Benjamin Pasero 已提交
647
			if (this.editorGroupService.count > 1) {
648 649 650 651
				multipleEditorGroups.set(true);
			} else {
				multipleEditorGroups.reset();
			}
652 653 654 655 656 657

			if (activeControl) {
				activeEditorContext.set(activeControl.getId());
			} else {
				activeEditorContext.reset();
			}
658
		};
B
Benjamin Pasero 已提交
659

660
		this.editorPart.whenRestored.then(() => updateEditorContextKeys());
661 662
		this._register(this.editorService.onDidActiveEditorChange(() => updateEditorContextKeys()));
		this._register(this.editorService.onDidVisibleEditorsChange(() => updateEditorContextKeys()));
B
Benjamin Pasero 已提交
663 664
		this._register(this.editorGroupService.onDidAddGroup(() => updateEditorContextKeys()));
		this._register(this.editorGroupService.onDidRemoveGroup(() => updateEditorContextKeys()));
665

666 667 668 669 670 671 672 673 674 675
		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 已提交
676

677 678 679 680 681
		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);
		}));
682

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

685 686 687 688
		const updateSplitEditorsVerticallyContext = () => {
			const direction = preferredSideBySideGroupDirection(this.configurationService);
			splitEditorsVerticallyContext.set(direction === GroupDirection.DOWN);
		};
S
Sanders Lauture 已提交
689

690 691 692 693 694
		this._register(this.configurationService.onDidChangeConfiguration(e => {
			if (e.affectsConfiguration('workbench.editor.openSideBySideDirection')) {
				updateSplitEditorsVerticallyContext();
			}
		}));
E
Erich Gamma 已提交
695

696
		updateSplitEditorsVerticallyContext();
697
	}
E
Erich Gamma 已提交
698

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

702 703
		// Restore Editorpart
		perf.mark('willRestoreEditors');
704
		restorePromises.push(this.editorPart.whenRestored.then(() => {
705 706
			return this.resolveEditorsToOpen().then(inputs => {
				if (inputs.length) {
707
					return this.editorService.openEditors(inputs);
708
				}
E
Erich Gamma 已提交
709

710 711 712 713 714
				return TPromise.as(void 0);
			});
		}).then(() => {
			perf.mark('didRestoreEditors');
		}));
E
Erich Gamma 已提交
715

716 717 718 719
		// Restore Sidebar
		let viewletIdToRestore: string;
		if (!this.sideBarHidden) {
			this.sideBarVisibleContext.set(true);
720

721 722
			if (this.shouldRestoreLastOpenedViewlet()) {
				viewletIdToRestore = this.storageService.get(SidebarPart.activeViewletSettingsKey, StorageScope.WORKSPACE);
723
			}
724

725 726
			if (!viewletIdToRestore) {
				viewletIdToRestore = this.viewletService.getDefaultViewletId();
727
			}
E
Erich Gamma 已提交
728

729
			perf.mark('willRestoreViewlet');
730 731 732 733 734
			restorePromises.push(this.viewletService.openViewlet(viewletIdToRestore)
				.then(viewlet => viewlet || this.viewletService.openViewlet(this.viewletService.getDefaultViewletId()))
				.then(() => {
					perf.mark('didRestoreViewlet');
				}));
735 736
		}

737 738 739 740
		// Restore Panel
		const panelRegistry = Registry.as<PanelRegistry>(PanelExtensions.Panels);
		const panelId = this.storageService.get(PanelPart.activePanelSettingsKey, StorageScope.WORKSPACE, panelRegistry.getDefaultPanelId());
		if (!this.panelHidden && !!panelId) {
741
			perf.mark('willRestorePanel');
742
			const isPanelToRestoreEnabled = !!this.panelPart.getPanels().filter(p => p.id === panelId).length;
743 744
			const panelIdToRestore = isPanelToRestoreEnabled ? panelId : panelRegistry.getDefaultPanelId();
			restorePromises.push(this.panelPart.openPanel(panelIdToRestore, false).then(() => perf.mark('didRestorePanel')));
I
isidor 已提交
745 746
		}

747
		// Restore Zen Mode if active
I
isidor 已提交
748
		if (this.storageService.getBoolean(Workbench.zenModeActiveStorageKey, StorageScope.WORKSPACE, false)) {
I
isidor 已提交
749
			this.toggleZenMode(true, true);
I
isidor 已提交
750 751
		}

B
Benjamin Pasero 已提交
752
		// Restore Forced Editor Center Mode
753
		if (this.storageService.getBoolean(Workbench.centeredEditorLayoutActiveStorageKey, StorageScope.WORKSPACE, false)) {
I
isidor 已提交
754
			this.centerEditorLayout(true);
S
SrTobi 已提交
755
		}
756

757
		const onRestored = (error?: Error): IWorkbenchStartedInfo => {
B
Benjamin Pasero 已提交
758
			this.workbenchCreated = true;
759

760 761
			if (error) {
				errors.onUnexpectedError(error);
762
			}
I
isidor 已提交
763

764 765 766 767
			return {
				customKeybindingsCount: this.keybindingService.customKeybindingsCount(),
				pinnedViewlets: this.activitybarPart.getPinned(),
				restoredViewlet: viewletIdToRestore,
768
				restoredEditorsCount: this.editorService.visibleEditors.length
769 770
			};
		};
771

772
		return TPromise.join(restorePromises).then(() => onRestored(), error => onRestored(error));
E
Erich Gamma 已提交
773 774
	}

775 776 777
	private shouldRestoreLastOpenedViewlet(): boolean {
		if (!this.environmentService.isBuilt) {
			return true; // always restore sidebar when we are in development mode
E
Erich Gamma 已提交
778 779
		}

780 781 782 783
		const restore = this.storageService.getBoolean(Workbench.sidebarRestoreStorageKey, StorageScope.WORKSPACE);
		if (restore) {
			this.storageService.remove(Workbench.sidebarRestoreStorageKey, StorageScope.WORKSPACE); // only support once
		}
784

785
		return restore;
E
Erich Gamma 已提交
786 787
	}

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

B
Benjamin Pasero 已提交
791
		// Files to open, diff or create
792
		if (this.hasInitialFilesToOpen) {
I
isidor 已提交
793

B
Benjamin Pasero 已提交
794
			// Files to diff is exclusive
795
			const filesToDiff = this.toInputs(config.filesToDiff, false);
796
			if (filesToDiff && filesToDiff.length === 2) {
797 798 799
				return TPromise.as([<IResourceDiffInput>{
					leftResource: filesToDiff[0].resource,
					rightResource: filesToDiff[1].resource,
B
Benjamin Pasero 已提交
800
					options: { pinned: true },
B
Benjamin Pasero 已提交
801
					forceFile: true
802
				}]);
B
Benjamin Pasero 已提交
803
			}
I
isidor 已提交
804

805 806
			const filesToCreate = this.toInputs(config.filesToCreate, true);
			const filesToOpen = this.toInputs(config.filesToOpen, false);
I
isidor 已提交
807

808 809
			// Otherwise: Open/Create files
			return TPromise.as([...filesToOpen, ...filesToCreate]);
B
Benjamin Pasero 已提交
810
		}
I
isidor 已提交
811

812
		// Empty workbench
813
		else if (this.contextService.getWorkbenchState() === WorkbenchState.EMPTY && this.openUntitledFile()) {
B
Benjamin Pasero 已提交
814
			const isEmpty = this.editorGroupService.count === 1 && this.editorGroupService.activeGroup.count === 0;
815 816
			if (!isEmpty) {
				return TPromise.as([]); // do not open any empty untitled file if we restored editors from previous session
817
			}
B
Benjamin Pasero 已提交
818

819 820 821 822
			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 已提交
823

824
				return TPromise.as([<IUntitledResourceInput>{}]);
825
			});
826
		}
827

B
Benjamin Pasero 已提交
828 829
		return TPromise.as([]);
	}
830

831
	private toInputs(paths: IPath[], isNew: boolean): (IResourceInput | IUntitledResourceInput)[] {
B
Benjamin Pasero 已提交
832 833
		if (!paths || !paths.length) {
			return [];
834
		}
I
isidor 已提交
835

B
Benjamin Pasero 已提交
836
		return paths.map(p => {
837
			const resource = p.fileUri;
838 839 840 841
			let input: IResourceInput | IUntitledResourceInput;
			if (isNew) {
				input = { filePath: resource.fsPath, options: { pinned: true } } as IUntitledResourceInput;
			} else {
B
Benjamin Pasero 已提交
842
				input = { resource, options: { pinned: true }, forceFile: true } as IResourceInput;
843
			}
E
Erich Gamma 已提交
844

845
			if (!isNew && p.lineNumber) {
B
Benjamin Pasero 已提交
846 847 848 849 850
				input.options.selection = {
					startLineNumber: p.lineNumber,
					startColumn: p.columnNumber
				};
			}
851

B
Benjamin Pasero 已提交
852 853
			return input;
		});
854 855
	}

856
	private openUntitledFile() {
857
		const startupEditor = this.configurationService.inspect('workbench.startupEditor');
B
Benjamin Pasero 已提交
858 859

		// Fallback to previous workbench.welcome.enabled setting in case startupEditor is not defined
860
		if (!startupEditor.user && !startupEditor.workspace) {
861 862 863
			const welcomeEnabledValue = this.configurationService.getValue('workbench.welcome.enabled');
			if (typeof welcomeEnabledValue === 'boolean') {
				return !welcomeEnabledValue;
864
			}
865
		}
E
Erich Gamma 已提交
866

867
		return startupEditor.value === 'newUntitledFile';
868
	}
E
Erich Gamma 已提交
869 870

	private initSettings(): void {
871

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

I
isidor 已提交
875
		// Panel part visibility
876
		const panelRegistry = Registry.as<PanelRegistry>(PanelExtensions.Panels);
I
isidor 已提交
877
		this.panelHidden = this.storageService.getBoolean(Workbench.panelHiddenStorageKey, StorageScope.WORKSPACE, true);
878 879
		if (!panelRegistry.getDefaultPanelId()) {
			this.panelHidden = true; // we hide panel part if there is no default panel
880 881
		}

E
Erich Gamma 已提交
882
		// Sidebar position
883
		const sideBarPosition = this.configurationService.getValue<string>(Workbench.sidebarPositionConfigurationKey);
884
		this.sideBarPosition = (sideBarPosition === 'right') ? Position.RIGHT : Position.LEFT;
885

I
isidor 已提交
886
		// Panel position
887
		this.setPanelPositionFromStorageOrConfig();
888

889
		// Menubar visibility
890
		const menuBarVisibility = this.configurationService.getValue<MenuBarVisibility>(Workbench.menubarVisibilityConfigurationKey);
S
SteVen Batten 已提交
891
		this.setMenubarVisibility(menuBarVisibility, true);
892

B
Benjamin Pasero 已提交
893
		// Statusbar visibility
894
		const statusBarVisible = this.configurationService.getValue<string>(Workbench.statusbarVisibleConfigurationKey);
895
		this.statusBarHidden = !statusBarVisible;
896

S
Sanders Lauture 已提交
897
		// Activity bar visibility
898
		const activityBarVisible = this.configurationService.getValue<string>(Workbench.activityBarVisibleConfigurationKey);
S
Sanders Lauture 已提交
899
		this.activityBarHidden = !activityBarVisible;
900

901
		// Font aliasing
902
		this.fontAliasing = this.configurationService.getValue<FontAliasingOption>(Workbench.fontAliasingConfigurationKey);
903

I
isidor 已提交
904 905
		// Zen mode
		this.zenMode = {
I
isidor 已提交
906
			active: false,
907
			transitionedToFullScreen: false,
908
			transitionedToCenteredEditorLayout: false,
909
			wasSideBarVisible: false,
910 911
			wasPanelVisible: false,
			transitionDisposeables: []
I
isidor 已提交
912
		};
E
Erich Gamma 已提交
913 914
	}

915 916 917 918 919
	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;
	}
920

921 922
	private getCustomTitleBarStyle(): 'custom' {
		const isDev = !this.environmentService.isBuilt || this.environmentService.isExtensionDevelopment;
B
Benjamin Pasero 已提交
923
		if (isMacintosh && isDev) {
924 925
			return null; // not enabled when developing due to https://github.com/electron/electron/issues/3647
		}
E
Erich Gamma 已提交
926

927 928 929 930 931 932 933 934 935 936
		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;
937 938 939
			}
		}

940
		return null;
B
Benjamin Pasero 已提交
941 942
	}

943 944
	private setStatusBarHidden(hidden: boolean, skipLayout?: boolean): void {
		this.statusBarHidden = hidden;
B
Benjamin Pasero 已提交
945

946 947
		// Adjust CSS
		if (hidden) {
B
Benjamin Pasero 已提交
948
			DOM.addClass(this.workbench, 'nostatusbar');
E
Erich Gamma 已提交
949
		} else {
B
Benjamin Pasero 已提交
950
			DOM.removeClass(this.workbench, 'nostatusbar');
E
Erich Gamma 已提交
951 952
		}

953 954 955
		// Layout
		if (!skipLayout) {
			this.workbenchLayout.layout();
956 957 958
		}
	}

959
	private setFontAliasing(aliasing: FontAliasingOption) {
960
		this.fontAliasing = aliasing;
S
Sanders Lauture 已提交
961

B
Benjamin Pasero 已提交
962 963 964 965 966
		// Remove all
		document.body.classList.remove(...fontAliasingValues.map(value => `monaco-font-aliasing-${value}`));

		// Add specific
		if (fontAliasingValues.some(option => option === aliasing)) {
967
			document.body.classList.add(`monaco-font-aliasing-${aliasing}`);
S
Sanders Lauture 已提交
968
		}
969 970
	}

E
Erich Gamma 已提交
971
	private createWorkbenchLayout(): void {
972 973
		this.workbenchLayout = this.instantiationService.createInstance(
			WorkbenchLayout,
974
			this.container,
B
Benjamin Pasero 已提交
975
			this.workbench,
I
isidor 已提交
976
			{
977 978 979 980 981 982
				titlebar: this.titlebarPart,
				activitybar: this.activitybarPart,
				editor: this.editorPart,
				sidebar: this.sidebarPart,
				panel: this.panelPart,
				statusbar: this.statusbarPart,
I
isidor 已提交
983
			},
984 985 986 987
			this.quickOpen,
			this.quickInput,
			this.notificationsCenter,
			this.notificationsToasts
E
Erich Gamma 已提交
988 989 990 991 992 993 994
		);
	}

	private renderWorkbench(): void {

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

998
		if (this.panelHidden) {
B
Benjamin Pasero 已提交
999
			DOM.addClass(this.workbench, 'nopanel');
1000
		}
B
Benjamin Pasero 已提交
1001

1002
		if (this.statusBarHidden) {
B
Benjamin Pasero 已提交
1003
			DOM.addClass(this.workbench, 'nostatusbar');
1004
		}
E
Erich Gamma 已提交
1005

B
Benjamin Pasero 已提交
1006
		// Apply font aliasing
1007 1008
		this.setFontAliasing(this.fontAliasing);

1009 1010
		// Apply fullscreen state
		if (browser.isFullscreen()) {
B
Benjamin Pasero 已提交
1011
			DOM.addClass(this.workbench, 'fullscreen');
B
Benjamin Pasero 已提交
1012 1013
		}

E
Erich Gamma 已提交
1014
		// Create Parts
B
Benjamin Pasero 已提交
1015
		this.createTitlebarPart();
E
Erich Gamma 已提交
1016 1017 1018
		this.createActivityBarPart();
		this.createSidebarPart();
		this.createEditorPart();
1019
		this.createPanelPart();
E
Erich Gamma 已提交
1020 1021
		this.createStatusbarPart();

1022 1023
		// Notification Handlers
		this.createNotificationsHandlers();
1024

1025 1026 1027 1028 1029 1030

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

E
Erich Gamma 已提交
1031
		// Add Workbench to DOM
B
Benjamin Pasero 已提交
1032
		this.container.appendChild(this.workbench);
E
Erich Gamma 已提交
1033 1034
	}

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

B
Benjamin Pasero 已提交
1038
		this.titlebarPart.create(titlebarContainer);
B
Benjamin Pasero 已提交
1039 1040
	}

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

B
Benjamin Pasero 已提交
1044
		this.activitybarPart.create(activitybarPartContainer);
E
Erich Gamma 已提交
1045 1046 1047
	}

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

B
Benjamin Pasero 已提交
1050
		this.sidebarPart.create(sidebarPartContainer);
E
Erich Gamma 已提交
1051 1052
	}

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

B
Benjamin Pasero 已提交
1056
		this.panelPart.create(panelPartContainer);
I
isidor 已提交
1057 1058
	}

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

B
Benjamin Pasero 已提交
1062
		this.editorPart.create(editorContainer);
E
Erich Gamma 已提交
1063 1064 1065
	}

	private createStatusbarPart(): void {
B
Benjamin Pasero 已提交
1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076
		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);

S
SteVen Batten 已提交
1077 1078 1079
		// Insert all workbench parts at the beginning. Issue #52531
		// This is primarily for the title bar to allow overriding -webkit-app-region
		this.workbench.insertBefore(part, this.workbench.lastChild);
E
Erich Gamma 已提交
1080

B
Benjamin Pasero 已提交
1081
		return part;
E
Erich Gamma 已提交
1082 1083
	}

1084 1085
	private createNotificationsHandlers(): void {

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

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

1092
		// Notifications Alerts
1093
		this._register(this.instantiationService.createInstance(NotificationsAlerts, this.notificationService.model));
1094 1095 1096 1097

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

1098
		// Eventing
1099
		this._register(this.notificationsCenter.onDidChangeVisibility(() => {
1100 1101 1102 1103 1104 1105 1106 1107

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

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

1108
		// Register Commands
1109
		registerNotificationCommands(this.notificationsCenter, this.notificationsToasts);
1110 1111
	}

1112
	getInstantiationService(): IInstantiationService {
E
Erich Gamma 已提交
1113 1114 1115
		return this.instantiationService;
	}

1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140
	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 已提交
1141
	private _onTitleBarVisibilityChange: Emitter<void> = this._register(new Emitter<void>());
1142
	get onTitleBarVisibilityChange(): Event<void> { return this._onTitleBarVisibilityChange.event; }
1143

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

1146
	isCreated(): boolean {
1147
		return !!(this.workbenchCreated && this.workbenchStarted);
1148
	}
1149

1150 1151 1152 1153 1154
	hasFocus(part: Parts): boolean {
		const activeElement = document.activeElement;
		if (!activeElement) {
			return false;
		}
1155

1156 1157 1158
		const container = this.getContainer(part);
		return DOM.isAncestor(activeElement, container);
	}
1159

1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181
	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;
		}
1182

1183 1184
		return container;
	}
1185

1186 1187 1188
	isVisible(part: Parts): boolean {
		switch (part) {
			case Parts.TITLEBAR_PART:
1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201
				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;
1202 1203 1204 1205 1206 1207 1208 1209
			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 已提交
1210
		}
1211

1212
		return true; // any other part cannot be hidden
E
Erich Gamma 已提交
1213 1214
	}

1215 1216 1217
	getTitleBarOffset(): number {
		let offset = 0;
		if (this.isVisible(Parts.TITLEBAR_PART)) {
S
SteVen Batten 已提交
1218
			offset = this.workbenchLayout.partLayoutInfo.titlebar.height;
1219 1220 1221
			if (isMacintosh || this.menubarVisibility === 'hidden') {
				offset /= browser.getZoomFactor();
			}
E
Erich Gamma 已提交
1222
		}
1223 1224

		return offset;
E
Erich Gamma 已提交
1225
	}
1226

1227 1228
	getWorkbenchElement(): HTMLElement {
		return this.workbench;
1229
	}
1230

I
isidor 已提交
1231
	toggleZenMode(skipLayout?: boolean, restoring = false): void {
I
isidor 已提交
1232
		this.zenMode.active = !this.zenMode.active;
1233
		this.zenMode.transitionDisposeables = dispose(this.zenMode.transitionDisposeables);
1234

1235 1236
		// 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)
1237
		let toggleFullScreen = false;
1238 1239

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

I
isidor 已提交
1243
			toggleFullScreen = !browser.isFullscreen() && config.fullScreen;
I
isidor 已提交
1244
			this.zenMode.transitionedToFullScreen = restoring ? config.fullScreen : toggleFullScreen;
1245
			this.zenMode.transitionedToCenteredEditorLayout = !this.isEditorLayoutCentered() && config.centerLayout;
1246 1247
			this.zenMode.wasSideBarVisible = this.isVisible(Parts.SIDEBAR_PART);
			this.zenMode.wasPanelVisible = this.isVisible(Parts.PANEL_PART);
1248

1249 1250
			this.setPanelHidden(true, true);
			this.setSideBarHidden(true, true);
I
isidor 已提交
1251

1252 1253 1254
			if (config.hideActivityBar) {
				this.setActivityBarHidden(true, true);
			}
1255

I
isidor 已提交
1256
			if (config.hideStatusBar) {
I
isidor 已提交
1257 1258
				this.setStatusBarHidden(true, true);
			}
1259

1260 1261
			if (config.hideTabs && this.editorPart.partOptions.showTabs) {
				this.zenMode.transitionDisposeables.push(this.editorPart.enforcePartOptions({ showTabs: false }));
I
isidor 已提交
1262
			}
1263 1264 1265 1266

			if (config.centerLayout) {
				this.centerEditorLayout(true, true);
			}
1267 1268 1269 1270
		}

		// Zen Mode Inactive
		else {
1271
			if (this.zenMode.wasPanelVisible) {
1272
				this.setPanelHidden(false, true);
1273
			}
1274

1275
			if (this.zenMode.wasSideBarVisible) {
1276
				this.setSideBarHidden(false, true);
1277
			}
1278

1279 1280 1281
			if (this.zenMode.transitionedToCenteredEditorLayout) {
				this.centerEditorLayout(false, true);
			}
1282

1283 1284
			// Status bar and activity bar visibility come from settings -> update their visibility.
			this.onDidUpdateConfiguration(true);
1285

B
Benjamin Pasero 已提交
1286
			this.editorGroupService.activeGroup.focus();
1287

1288
			toggleFullScreen = this.zenMode.transitionedToFullScreen && browser.isFullscreen();
I
isidor 已提交
1289
		}
1290

1291
		this.inZenMode.set(this.zenMode.active);
I
isidor 已提交
1292

I
isidor 已提交
1293
		if (!skipLayout) {
1294
			this.layout();
I
isidor 已提交
1295
		}
1296

1297
		if (toggleFullScreen) {
1298
			this.windowService.toggleFullScreen();
1299
		}
I
isidor 已提交
1300 1301
	}

1302
	layout(options?: ILayoutOptions): void {
J
Joao Moreno 已提交
1303 1304
		this.contextViewService.layout();

1305 1306 1307 1308 1309
		if (this.workbenchStarted && !this.workbenchShutdown) {
			this.workbenchLayout.layout(options);
		}
	}

1310
	isEditorLayoutCentered(): boolean {
I
isidor 已提交
1311
		return this.editorPart.isLayoutCentered();
S
SrTobi 已提交
1312 1313
	}

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

1317
		// Enter Centered Editor Layout
I
isidor 已提交
1318
		this.editorPart.centerLayout(active);
1319

1320 1321 1322
		if (!skipLayout) {
			this.layout();
		}
S
SrTobi 已提交
1323 1324
	}

1325
	resizePart(part: Parts, sizeChange: number): void {
1326 1327 1328 1329 1330 1331 1332
		switch (part) {
			case Parts.SIDEBAR_PART:
			case Parts.PANEL_PART:
			case Parts.EDITOR_PART:
				this.workbenchLayout.resizePart(part, sizeChange);
				break;
			default:
B
Benjamin Pasero 已提交
1333
				return; // Cannot resize other parts
1334 1335 1336
		}
	}

1337 1338
	setActivityBarHidden(hidden: boolean, skipLayout?: boolean): void {
		this.activityBarHidden = hidden;
1339

1340 1341 1342
		// Layout
		if (!skipLayout) {
			this.workbenchLayout.layout();
1343
		}
1344
	}
1345

1346 1347 1348 1349 1350 1351
	setSideBarHidden(hidden: boolean, skipLayout?: boolean): TPromise<void> {
		this.sideBarHidden = hidden;
		this.sideBarVisibleContext.set(!hidden);

		// Adjust CSS
		if (hidden) {
B
Benjamin Pasero 已提交
1352
			DOM.addClass(this.workbench, 'nosidebar');
1353
		} else {
B
Benjamin Pasero 已提交
1354
			DOM.removeClass(this.workbench, 'nosidebar');
1355 1356
		}

1357 1358 1359 1360 1361 1362 1363 1364 1365
		// 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 已提交
1366 1367
				} else {
					this.editorGroupService.activeGroup.focus();
1368 1369 1370 1371 1372 1373 1374 1375
				}
			});
		}

		// If sidebar becomes visible, show last active Viewlet or default viewlet
		else if (!hidden && !this.sidebarPart.getActiveViewlet()) {
			const viewletToOpen = this.sidebarPart.getLastActiveViewletId();
			if (viewletToOpen) {
1376 1377
				promise = this.viewletService.openViewlet(viewletToOpen, true)
					.then(viewlet => viewlet || this.viewletService.openViewlet(this.viewletService.getDefaultViewletId(), true));
1378
			}
1379 1380
		}

1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395
		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();
			}
		});
1396
	}
1397 1398 1399 1400 1401 1402

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

		// Adjust CSS
		if (hidden) {
B
Benjamin Pasero 已提交
1403
			DOM.addClass(this.workbench, 'nopanel');
1404
		} else {
B
Benjamin Pasero 已提交
1405
			DOM.removeClass(this.workbench, 'nopanel');
1406 1407 1408 1409 1410 1411
		}

		// 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 已提交
1412
				this.editorGroupService.activeGroup.focus(); // Pass focus to editor group if panel part is now hidden
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
			});
		}

		// 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) {
1454
			this.setSideBarHidden(false, true /* Skip Layout */);
1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474
		}

		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 已提交
1475
	setMenubarVisibility(visibility: MenuBarVisibility, skipLayout: boolean): void {
S
SteVen Batten 已提交
1476 1477
		if (this.menubarVisibility !== visibility) {
			this.menubarVisibility = visibility;
1478

S
SteVen Batten 已提交
1479 1480 1481
			if (!skipLayout) {
				this.workbenchLayout.layout();
			}
1482 1483 1484
		}
	}

S
SteVen Batten 已提交
1485 1486 1487 1488
	getMenubarVisibility(): MenuBarVisibility {
		return this.menubarVisibility;
	}

1489 1490 1491 1492 1493 1494 1495 1496 1497
	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;
A
Alex Dima 已提交
1498
			this.storageService.store(Workbench.panelPositionStorageKey, PositionToString(this.panelPosition).toLowerCase(), StorageScope.WORKSPACE);
1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509

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

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

			// Layout
			this.workbenchLayout.layout();
		});
1510
	}
1511 1512

	//#endregion
I
isidor 已提交
1513
}