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

'use strict';

B
Benjamin Pasero 已提交
8
import 'vs/css!./media/activitybarpart';
9
import nls = require('vs/nls');
A
Alex Dima 已提交
10
import {TPromise} from 'vs/base/common/winjs.base';
E
Erich Gamma 已提交
11
import {Builder, $} from 'vs/base/browser/builder';
A
tslint  
Alex Dima 已提交
12
import {Action} from 'vs/base/common/actions';
E
Erich Gamma 已提交
13 14 15
import errors = require('vs/base/common/errors');
import {ActionsOrientation, ActionBar, IActionItem} from 'vs/base/browser/ui/actionbar/actionbar';
import {Registry} from 'vs/platform/platform';
16 17
import {IComposite} from 'vs/workbench/common/composite';
import {IPanel} from 'vs/workbench/common/panel';
I
isidor 已提交
18
import {ViewletDescriptor, ViewletRegistry, Extensions as ViewletExtensions, Viewlet} from 'vs/workbench/browser/viewlet';
19 20
import {CompositeDescriptor} from 'vs/workbench/browser/composite';
import {Panel, PanelRegistry, Extensions as PanelExtensions, PanelDescriptor} from 'vs/workbench/browser/panel';
E
Erich Gamma 已提交
21 22
import {Part} from 'vs/workbench/browser/part';
import {ActivityAction, ActivityActionItem} from 'vs/workbench/browser/parts/activitybar/activityAction';
23
import {TogglePanelAction} from 'vs/workbench/browser/parts/panel/panelPart';
E
Erich Gamma 已提交
24
import {IViewletService} from 'vs/workbench/services/viewlet/common/viewletService';
I
isidor 已提交
25
import {IPanelService} from 'vs/workbench/services/panel/common/panelService';
E
Erich Gamma 已提交
26 27 28 29
import {IActivityService, IBadge} from 'vs/workbench/services/activity/common/activityService';
import {IPartService} from 'vs/workbench/services/part/common/partService';
import {IContextMenuService} from 'vs/platform/contextview/browser/contextView';
import {IInstantiationService} from 'vs/platform/instantiation/common/instantiation';
A
tslint  
Alex Dima 已提交
30
import {IMessageService} from 'vs/platform/message/common/message';
E
Erich Gamma 已提交
31
import {ITelemetryService} from 'vs/platform/telemetry/common/telemetry';
32
import {IKeybindingService} from 'vs/platform/keybinding/common/keybinding';
E
Erich Gamma 已提交
33 34

export class ActivitybarPart extends Part implements IActivityService {
35
	public _serviceBrand: any;
I
isidor 已提交
36 37
	private viewletSwitcherBar: ActionBar;
	private panelSwitcherBar: ActionBar;
E
Erich Gamma 已提交
38
	private activityActionItems: { [actionId: string]: IActionItem; };
39
	private compositeIdToActions: { [compositeId: string]: ActivityAction; };
40
	private panelActions: ActivityAction[];
41
	private showPanelAction: TogglePanelAction;
E
Erich Gamma 已提交
42 43

	constructor(
44 45
		id: string,
		@IViewletService private viewletService: IViewletService,
46
		@IPanelService private panelService: IPanelService,
47 48 49
		@IMessageService private messageService: IMessageService,
		@ITelemetryService private telemetryService: ITelemetryService,
		@IContextMenuService private contextMenuService: IContextMenuService,
50
		@IKeybindingService private keybindingService: IKeybindingService,
I
isidor 已提交
51 52
		@IInstantiationService private instantiationService: IInstantiationService,
		@IPartService private partService: IPartService
E
Erich Gamma 已提交
53 54 55 56
	) {
		super(id);

		this.activityActionItems = {};
57
		this.compositeIdToActions = {};
E
Erich Gamma 已提交
58 59 60 61 62 63 64

		this.registerListeners();
	}

	private registerListeners(): void {

		// Activate viewlet action on opening of a viewlet
65 66
		this.toUnbind.push(this.viewletService.onDidViewletOpen(viewlet => this.onActiveCompositeChanged(viewlet)));
		this.toUnbind.push(this.panelService.onDidPanelOpen(panel => this.onActivePanelChanged(panel)));
E
Erich Gamma 已提交
67 68

		// Deactivate viewlet action on close
69 70
		this.toUnbind.push(this.viewletService.onDidViewletClose(viewlet => this.onCompositeClosed(viewlet)));
		this.toUnbind.push(this.panelService.onDidPanelClose(panel => this.onPanelClosed(panel)));
E
Erich Gamma 已提交
71 72
	}

73 74 75
	private onActiveCompositeChanged(composite: IComposite): void {
		if (this.compositeIdToActions[composite.getId()]) {
			this.compositeIdToActions[composite.getId()].activate();
E
Erich Gamma 已提交
76 77 78
		}
	}

79
	private onActivePanelChanged(panel: IPanel): void {
I
isidor 已提交
80
		this.updatePanelSwitcher();
81 82 83 84 85 86
		this.onActiveCompositeChanged(panel);
	}

	private onCompositeClosed(composite: IComposite): void {
		if (this.compositeIdToActions[composite.getId()]) {
			this.compositeIdToActions[composite.getId()].deactivate();
E
Erich Gamma 已提交
87 88 89
		}
	}

90
	private onPanelClosed(panel: IPanel): void {
I
isidor 已提交
91
		this.updatePanelSwitcher();
92 93 94
		this.onCompositeClosed(panel);
	}

95 96
	public showActivity(compositeId: string, badge: IBadge, clazz?: string): void {
		const action = this.compositeIdToActions[compositeId];
E
Erich Gamma 已提交
97 98 99 100 101 102 103 104
		if (action) {
			action.setBadge(badge);
			if (clazz) {
				action.class = clazz;
			}
		}
	}

105 106
	public clearActivity(compositeId: string): void {
		this.showActivity(compositeId, null);
E
Erich Gamma 已提交
107 108 109
	}

	public createContentArea(parent: Builder): Builder {
110 111
		const $el = $(parent);
		const $result = $('.content').appendTo($el);
E
Erich Gamma 已提交
112 113

		// Top Actionbar with action items for each viewlet action
I
isidor 已提交
114 115
		this.createViewletSwitcher($result.clone());
		this.createPanelSwitcher($result.clone());
E
Erich Gamma 已提交
116 117 118 119

		return $result;
	}

I
isidor 已提交
120
	private createViewletSwitcher(div: Builder): void {
E
Erich Gamma 已提交
121

122
		// Composite switcher is on top
I
isidor 已提交
123
		this.viewletSwitcherBar = new ActionBar(div, {
124
			actionItemProvider: (action: Action) => this.activityActionItems[action.id],
125 126
			orientation: ActionsOrientation.VERTICAL,
			ariaLabel: nls.localize('activityBarAriaLabel', "Active View Switcher")
E
Erich Gamma 已提交
127
		});
I
isidor 已提交
128
		this.viewletSwitcherBar.getContainer().addClass('position-top');
E
Erich Gamma 已提交
129

J
Joao Moreno 已提交
130
		// Build Viewlet Actions in correct order
I
isidor 已提交
131
		const allViewlets = (<ViewletRegistry>Registry.as(ViewletExtensions.Viewlets)).getViewlets();
I
isidor 已提交
132
		const viewletActions = allViewlets.sort((v1, v2) => v1.order - v2.order).map(viewlet => this.toAction(viewlet));
J
Joao Moreno 已提交
133

I
isidor 已提交
134 135
		this.viewletSwitcherBar.push(viewletActions, { label: true, icon: true });
	}
J
Joao Moreno 已提交
136

I
isidor 已提交
137
	private createPanelSwitcher(div: Builder): void {
E
Erich Gamma 已提交
138

I
isidor 已提交
139 140 141 142 143 144 145
		// Composite switcher is on top
		this.panelSwitcherBar = new ActionBar(div, {
			actionItemProvider: (action: Action) => this.activityActionItems[action.id],
			orientation: ActionsOrientation.VERTICAL,
			ariaLabel: nls.localize('activityBarPanelAriaLabel', "Active Panel Switcher")
		});
		this.panelSwitcherBar.getContainer().addClass('position-bottom');
E
Erich Gamma 已提交
146

I
isidor 已提交
147 148 149
		// Build Viewlet Actions in correct order

		const allPanels = (<PanelRegistry>Registry.as(PanelExtensions.Panels)).getPanels();
J
Joao Moreno 已提交
150

151
		this.showPanelAction = this.instantiationService.createInstance(TogglePanelAction, TogglePanelAction.ID, TogglePanelAction.LABEL);
152
		this.activityActionItems[this.showPanelAction.id] = new ActivityActionItem(this.showPanelAction);
I
isidor 已提交
153
		this.panelActions = allPanels.sort((p1, p2) => p1.order - p2.order).map(panel => this.toAction(panel));
J
Joao Moreno 已提交
154

I
isidor 已提交
155
		// Add both viewlet and panel actions to the switcher
I
isidor 已提交
156
		this.updatePanelSwitcher();
I
isidor 已提交
157 158
	}

I
isidor 已提交
159 160
	private updatePanelSwitcher(): void {
		this.panelSwitcherBar.clear();
161 162 163 164
		const actions:ActivityAction[] = [this.showPanelAction];
		if (!this.partService.isPanelHidden()) {
			actions.push(...this.panelActions);
		}
I
isidor 已提交
165

I
isidor 已提交
166
		this.panelSwitcherBar.push(actions, { label: true, icon: true });
J
Joao Moreno 已提交
167 168
	}

I
isidor 已提交
169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191
	private toAction(composite: CompositeDescriptor<Viewlet | Panel>): ActivityAction {
		const activeViewlet = this.viewletService.getActiveViewlet();
		const activePanel = this.panelService.getActivePanel();
		const action = composite instanceof ViewletDescriptor ? this.instantiationService.createInstance(ViewletActivityAction, composite.id + '.activity-bar-action', composite)
			: this.instantiationService.createInstance(PanelActivityAction, composite.id + '.activity-bar-action', composite);

		let keybinding: string = null;
		const keys = this.keybindingService.lookupKeybindings(composite.id).map(k => this.keybindingService.getLabelFor(k));
		if (keys && keys.length) {
			keybinding = keys[0];
		}

		this.activityActionItems[action.id] = new ActivityActionItem(action, composite.name, keybinding);
		this.compositeIdToActions[composite.id] = action;

		// Mark active viewlet and panel action as active
		if (activeViewlet && activeViewlet.getId() === composite.id || activePanel && activePanel.getId() === composite.id) {
			action.activate();
		}

		return action;
	};

E
Erich Gamma 已提交
192
	public dispose(): void {
I
isidor 已提交
193 194 195 196 197 198 199 200
		if (this.viewletSwitcherBar) {
			this.viewletSwitcherBar.dispose();
			this.viewletSwitcherBar = null;
		}

		if (this.panelSwitcherBar) {
			this.panelSwitcherBar.dispose();
			this.panelSwitcherBar = null;
E
Erich Gamma 已提交
201 202
		}

203 204
		if (this.showPanelAction) {
			this.showPanelAction.dispose();
E
Erich Gamma 已提交
205 206 207 208 209 210
		}

		super.dispose();
	}
}

211
class ViewletActivityAction extends ActivityAction {
E
Erich Gamma 已提交
212
	private static preventDoubleClickDelay = 300;
213
	private lastRun: number = 0;
E
Erich Gamma 已提交
214 215

	constructor(
216 217 218
		id: string, private viewlet: ViewletDescriptor,
		@IViewletService private viewletService: IViewletService,
		@IPartService private partService: IPartService
E
Erich Gamma 已提交
219
	) {
220
		super(id, viewlet.name, viewlet.cssClass);
E
Erich Gamma 已提交
221 222
	}

A
Alex Dima 已提交
223
	public run(): TPromise<any> {
E
Erich Gamma 已提交
224

225
		// prevent accident trigger on a doubleclick (to help nervous people)
226
		const now = Date.now();
227
		if (now - this.lastRun < ViewletActivityAction.preventDoubleClickDelay) {
A
Alex Dima 已提交
228
			return TPromise.as(true);
E
Erich Gamma 已提交
229
		}
230
		this.lastRun = now;
E
Erich Gamma 已提交
231

I
isidor 已提交
232 233
		const sideBarHidden = this.partService.isSideBarHidden();
		const activeViewlet = this.viewletService.getActiveViewlet();
E
Erich Gamma 已提交
234 235

		// Hide sidebar if selected viewlet already visible
236
		if (!sideBarHidden && activeViewlet && activeViewlet.getId() === this.viewlet.id) {
E
Erich Gamma 已提交
237
			this.partService.setSideBarHidden(true);
I
isidor 已提交
238
		} else {
239
			this.viewletService.openViewlet(this.viewlet.id, true).done(null, errors.onUnexpectedError);
I
isidor 已提交
240
			this.activate();
E
Erich Gamma 已提交
241
		}
242 243

		return TPromise.as(true);
I
isidor 已提交
244 245 246
	}
}

247
class PanelActivityAction extends ActivityAction {
E
Erich Gamma 已提交
248

249 250 251 252 253 254
	constructor(
		id: string, private panel: PanelDescriptor,
		@IPanelService private panelService: IPanelService
	) {
		super(id, panel.name, panel.cssClass);
	}
I
isidor 已提交
255

256 257
	public run(): TPromise<any> {
		return this.panelService.openPanel(this.panel.id, true).then(() => this.activate());
E
Erich Gamma 已提交
258
	}
I
isidor 已提交
259
}