activitybarPart.ts 7.4 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');
J
Johannes Rieken 已提交
10 11 12
import { TPromise } from 'vs/base/common/winjs.base';
import { Builder, $ } from 'vs/base/browser/builder';
import { Action } from 'vs/base/common/actions';
E
Erich Gamma 已提交
13
import errors = require('vs/base/common/errors');
J
Johannes Rieken 已提交
14 15
import { ActionsOrientation, ActionBar, IActionItem } from 'vs/base/browser/ui/actionbar/actionbar';
import { IComposite } from 'vs/workbench/common/composite';
16
import { ViewletDescriptor } from 'vs/workbench/browser/viewlet';
J
Johannes Rieken 已提交
17 18
import { Part } from 'vs/workbench/browser/part';
import { ActivityAction, ActivityActionItem } from 'vs/workbench/browser/parts/activitybar/activityAction';
B
Benjamin Pasero 已提交
19
import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet';
J
Johannes Rieken 已提交
20
import { IActivityService, IBadge } from 'vs/workbench/services/activity/common/activityService';
21
import { IPartService, Parts } from 'vs/workbench/services/part/common/partService';
J
Johannes Rieken 已提交
22 23
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
E
Erich Gamma 已提交
24 25

export class ActivitybarPart extends Part implements IActivityService {
26
	public _serviceBrand: any;
P
Pine Wu 已提交
27

I
isidor 已提交
28
	private viewletSwitcherBar: ActionBar;
E
Erich Gamma 已提交
29
	private activityActionItems: { [actionId: string]: IActionItem; };
30
	private compositeIdToActions: { [compositeId: string]: ActivityAction; };
E
Erich Gamma 已提交
31 32

	constructor(
33 34
		id: string,
		@IViewletService private viewletService: IViewletService,
35
		@IKeybindingService private keybindingService: IKeybindingService,
I
isidor 已提交
36
		@IInstantiationService private instantiationService: IInstantiationService,
37
		@IPartService private partService: IPartService
E
Erich Gamma 已提交
38 39 40 41
	) {
		super(id);

		this.activityActionItems = {};
42
		this.compositeIdToActions = {};
E
Erich Gamma 已提交
43 44 45 46 47 48 49

		this.registerListeners();
	}

	private registerListeners(): void {

		// Activate viewlet action on opening of a viewlet
50
		this.toUnbind.push(this.viewletService.onDidViewletOpen(viewlet => this.onActiveCompositeChanged(viewlet)));
E
Erich Gamma 已提交
51 52

		// Deactivate viewlet action on close
53
		this.toUnbind.push(this.viewletService.onDidViewletClose(viewlet => this.onCompositeClosed(viewlet)));
54

P
Pine Wu 已提交
55
		// Update viewlet switcher when external viewlets become ready
B
Benjamin Pasero 已提交
56
		this.toUnbind.push(this.viewletService.onDidExtensionViewletsLoad(() => this.refreshViewletSwitcher()));
57 58 59

		// Update viewlet switcher on toggling of a viewlet
		this.toUnbind.push(this.viewletService.onDidViewletToggle(() => this.refreshViewletSwitcher()));
P
Pine Wu 已提交
60 61
	}

62 63 64
	private onActiveCompositeChanged(composite: IComposite): void {
		if (this.compositeIdToActions[composite.getId()]) {
			this.compositeIdToActions[composite.getId()].activate();
E
Erich Gamma 已提交
65 66 67
		}
	}

68 69 70
	private onCompositeClosed(composite: IComposite): void {
		if (this.compositeIdToActions[composite.getId()]) {
			this.compositeIdToActions[composite.getId()].deactivate();
E
Erich Gamma 已提交
71 72 73
		}
	}

74 75
	public showActivity(compositeId: string, badge: IBadge, clazz?: string): void {
		const action = this.compositeIdToActions[compositeId];
E
Erich Gamma 已提交
76 77 78 79 80 81 82 83
		if (action) {
			action.setBadge(badge);
			if (clazz) {
				action.class = clazz;
			}
		}
	}

84 85
	public clearActivity(compositeId: string): void {
		this.showActivity(compositeId, null);
E
Erich Gamma 已提交
86 87 88
	}

	public createContentArea(parent: Builder): Builder {
89 90
		const $el = $(parent);
		const $result = $('.content').appendTo($el);
E
Erich Gamma 已提交
91 92

		// Top Actionbar with action items for each viewlet action
P
Pine Wu 已提交
93
		this.createViewletSwitcher($result.clone());
E
Erich Gamma 已提交
94 95 96 97

		return $result;
	}

I
isidor 已提交
98 99
	private createViewletSwitcher(div: Builder): void {
		this.viewletSwitcherBar = new ActionBar(div, {
100
			actionItemProvider: (action: Action) => this.activityActionItems[action.id],
101 102
			orientation: ActionsOrientation.VERTICAL,
			ariaLabel: nls.localize('activityBarAriaLabel', "Active View Switcher")
E
Erich Gamma 已提交
103 104
		});

105
		this.fillViewletSwitcher(this.viewletService.getAllViewletsToDisplay());
P
Pine Wu 已提交
106
	}
J
Joao Moreno 已提交
107

P
Pine Wu 已提交
108
	private refreshViewletSwitcher(): void {
109
		this.fillViewletSwitcher(this.viewletService.getAllViewletsToDisplay());
P
Pine Wu 已提交
110 111
	}

P
Pine Wu 已提交
112
	private fillViewletSwitcher(viewlets: ViewletDescriptor[]) {
113

P
Pine Wu 已提交
114
		// Pull out viewlets no longer needed
P
Pine Wu 已提交
115 116 117
		const newViewletIds = viewlets.map(v => v.id);
		const existingViewletIds = Object.keys(this.compositeIdToActions);
		existingViewletIds.forEach(viewletId => {
P
Pine Wu 已提交
118 119 120 121 122
			if (newViewletIds.indexOf(viewletId) === -1) {
				this.pullViewlet(viewletId);
			}
		});

123
		// Built actions for viewlets to show
P
Pine Wu 已提交
124
		const actionsToPush = viewlets
P
Pine Wu 已提交
125 126 127
			.filter(viewlet => !this.compositeIdToActions[viewlet.id])
			.map(viewlet => this.toAction(viewlet));

128
		// Add to viewlet switcher
P
Pine Wu 已提交
129
		this.viewletSwitcherBar.push(actionsToPush, { label: true, icon: true });
130 131 132 133 134 135 136 137 138

		// Make sure to activate the active one
		const activeViewlet = this.viewletService.getActiveViewlet();
		if (activeViewlet) {
			const activeViewletEntry = this.compositeIdToActions[activeViewlet.getId()];
			if (activeViewletEntry) {
				activeViewletEntry.activate();
			}
		}
P
Pine Wu 已提交
139 140 141 142
	}

	private pullViewlet(viewletId: string): void {
		const index = Object.keys(this.compositeIdToActions).indexOf(viewletId);
143

P
Pine Wu 已提交
144 145
		const action = this.compositeIdToActions[viewletId];
		action.dispose();
146 147 148
		delete this.compositeIdToActions[viewletId];

		const actionItem = this.activityActionItems[action.id];
P
Pine Wu 已提交
149
		actionItem.dispose();
150 151
		delete this.activityActionItems[action.id];

P
Pine Wu 已提交
152
		this.viewletSwitcherBar.pull(index);
I
isidor 已提交
153
	}
J
Joao Moreno 已提交
154

I
isidor 已提交
155
	private toAction(composite: ViewletDescriptor): ActivityAction {
156
		const action = this.instantiationService.createInstance(ViewletActivityAction, `${composite.id}.activity-bar-action`, composite);
I
isidor 已提交
157

158
		this.activityActionItems[action.id] = new ActivityActionItem(action, composite.name, this.getKeybindingLabel(composite.id));
I
isidor 已提交
159 160 161 162 163
		this.compositeIdToActions[composite.id] = action;

		return action;
	};

164 165 166 167 168 169 170 171 172
	private getKeybindingLabel(id: string): string {
		const keys = this.keybindingService.lookupKeybindings(id).map(k => this.keybindingService.getLabelFor(k));
		if (keys && keys.length) {
			return keys[0];
		}

		return null;
	}

E
Erich Gamma 已提交
173
	public dispose(): void {
I
isidor 已提交
174 175 176 177 178
		if (this.viewletSwitcherBar) {
			this.viewletSwitcherBar.dispose();
			this.viewletSwitcherBar = null;
		}

E
Erich Gamma 已提交
179 180 181 182
		super.dispose();
	}
}

183
class ViewletActivityAction extends ActivityAction {
E
Erich Gamma 已提交
184
	private static preventDoubleClickDelay = 300;
185
	private lastRun: number = 0;
E
Erich Gamma 已提交
186 187

	constructor(
188 189
		id: string,
		private viewlet: ViewletDescriptor,
190 191
		@IViewletService private viewletService: IViewletService,
		@IPartService private partService: IPartService
E
Erich Gamma 已提交
192
	) {
193
		super(id, viewlet.name, viewlet.cssClass);
E
Erich Gamma 已提交
194 195
	}

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

198
		// prevent accident trigger on a doubleclick (to help nervous people)
199
		const now = Date.now();
200
		if (now - this.lastRun < ViewletActivityAction.preventDoubleClickDelay) {
A
Alex Dima 已提交
201
			return TPromise.as(true);
E
Erich Gamma 已提交
202
		}
203
		this.lastRun = now;
E
Erich Gamma 已提交
204

205
		const sideBarVisible = this.partService.isVisible(Parts.SIDEBAR_PART);
I
isidor 已提交
206
		const activeViewlet = this.viewletService.getActiveViewlet();
E
Erich Gamma 已提交
207 208

		// Hide sidebar if selected viewlet already visible
209
		if (sideBarVisible && activeViewlet && activeViewlet.getId() === this.viewlet.id) {
E
Erich Gamma 已提交
210
			this.partService.setSideBarHidden(true);
I
isidor 已提交
211
		} else {
212
			this.viewletService.openViewlet(this.viewlet.id, true).done(null, errors.onUnexpectedError);
I
isidor 已提交
213
			this.activate();
E
Erich Gamma 已提交
214
		}
215 216

		return TPromise.as(true);
I
isidor 已提交
217 218
	}
}