activitybarPart.ts 8.2 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 16 17 18 19 20 21 22 23 24
import { ActionsOrientation, ActionBar, IActionItem } from 'vs/base/browser/ui/actionbar/actionbar';
import { Registry } from 'vs/platform/platform';
import { IComposite } from 'vs/workbench/common/composite';
import { ViewletDescriptor, ViewletRegistry, Extensions as ViewletExtensions } from 'vs/workbench/browser/viewlet';
import { Part } from 'vs/workbench/browser/part';
import { ActivityAction, ActivityActionItem } from 'vs/workbench/browser/parts/activitybar/activityAction';
import { IViewletService } from 'vs/workbench/services/viewlet/common/viewletService';
import { IActivityService, IBadge } from 'vs/workbench/services/activity/common/activityService';
import { IPartService } from 'vs/workbench/services/part/common/partService';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
P
Pine Wu 已提交
25
import { IStorageService } from 'vs/platform/storage/common/storage';
E
Erich Gamma 已提交
26 27

export class ActivitybarPart extends Part implements IActivityService {
28
	public _serviceBrand: any;
I
isidor 已提交
29
	private viewletSwitcherBar: ActionBar;
E
Erich Gamma 已提交
30
	private activityActionItems: { [actionId: string]: IActionItem; };
31
	private compositeIdToActions: { [compositeId: string]: ActivityAction; };
E
Erich Gamma 已提交
32

33
	private viewletsToggleStatus: { [viewletId: string]: boolean; };
34
	private registeredViewlets: string[];
35

P
Pine Wu 已提交
36
	private VIEWLETS_TOGGLE_STATUS = "workbench.activityBar.viewletsToggleStatus";
37

E
Erich Gamma 已提交
38
	constructor(
39 40
		id: string,
		@IViewletService private viewletService: IViewletService,
41
		@IKeybindingService private keybindingService: IKeybindingService,
I
isidor 已提交
42
		@IInstantiationService private instantiationService: IInstantiationService,
P
Pine Wu 已提交
43 44
		@IPartService private partService: IPartService,
		@IStorageService private storageService: IStorageService
E
Erich Gamma 已提交
45 46 47 48
	) {
		super(id);

		this.activityActionItems = {};
49
		this.compositeIdToActions = {};
E
Erich Gamma 已提交
50

51 52 53 54
		const viewletsToggleStatusJson = this.storageService.get(this.VIEWLETS_TOGGLE_STATUS);
		this.viewletsToggleStatus = viewletsToggleStatusJson ? JSON.parse(viewletsToggleStatusJson) : {};

		this.registeredViewlets = [];
55

E
Erich Gamma 已提交
56 57 58 59 60 61
		this.registerListeners();
	}

	private registerListeners(): void {

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

		// Deactivate viewlet action on close
65
		this.toUnbind.push(this.viewletService.onDidViewletClose(viewlet => this.onCompositeClosed(viewlet)));
66 67 68

		// Update activity bar on registering an external viewlet
		this.toUnbind.push(
69 70
			(<ViewletRegistry>Registry.as(ViewletExtensions.Viewlets))
				.onDidRegisterExternalViewlets(descriptors => this.onDidRegisterExternalViewlets(descriptors))
71 72 73
		);
	}

74 75
	private onDidRegisterExternalViewlets(descriptors: ViewletDescriptor[]) {
		descriptors.forEach(descriptor => {
76 77
			this.registeredViewlets.push(descriptor.id);
			if (this.viewletsToggleStatus[descriptor.id]) {
78 79
				this.viewletSwitcherBar.push(this.toAction(descriptor), { label: true, icon: true });
			}
P
Pine Wu 已提交
80
		});
E
Erich Gamma 已提交
81 82
	}

83 84 85
	private onActiveCompositeChanged(composite: IComposite): void {
		if (this.compositeIdToActions[composite.getId()]) {
			this.compositeIdToActions[composite.getId()].activate();
E
Erich Gamma 已提交
86 87 88
		}
	}

89 90 91
	private onCompositeClosed(composite: IComposite): void {
		if (this.compositeIdToActions[composite.getId()]) {
			this.compositeIdToActions[composite.getId()].deactivate();
E
Erich Gamma 已提交
92 93 94
		}
	}

95 96 97 98 99 100 101 102 103 104 105
	public getRegisteredViewletsToggleStatus(): { [viewletId: string]: boolean } {
		const result = {};
		this.registeredViewlets.forEach(viewletId => {
			result[viewletId] = this.viewletsToggleStatus[viewletId];
		});
		return result;
	}

	public toggleViewlet(viewletId: string): void {
		this.viewletsToggleStatus[viewletId] = !this.viewletsToggleStatus[viewletId];
		this.setViewletsToggleStatus();
P
Pine Wu 已提交
106
		this.refreshViewletSwitcher();
107 108 109 110
	}

	private setViewletsToggleStatus(): void {
		this.storageService.store(this.VIEWLETS_TOGGLE_STATUS, JSON.stringify(this.viewletsToggleStatus));
111 112
	}

113 114
	public showActivity(compositeId: string, badge: IBadge, clazz?: string): void {
		const action = this.compositeIdToActions[compositeId];
E
Erich Gamma 已提交
115 116 117 118 119 120 121 122
		if (action) {
			action.setBadge(badge);
			if (clazz) {
				action.class = clazz;
			}
		}
	}

123 124
	public clearActivity(compositeId: string): void {
		this.showActivity(compositeId, null);
E
Erich Gamma 已提交
125 126 127
	}

	public createContentArea(parent: Builder): Builder {
128 129
		const $el = $(parent);
		const $result = $('.content').appendTo($el);
E
Erich Gamma 已提交
130 131

		// Top Actionbar with action items for each viewlet action
P
Pine Wu 已提交
132
		this.createViewletSwitcher($result.clone().addClass('position-top'));
E
Erich Gamma 已提交
133 134 135 136

		return $result;
	}

I
isidor 已提交
137 138
	private createViewletSwitcher(div: Builder): void {
		this.viewletSwitcherBar = new ActionBar(div, {
139
			actionItemProvider: (action: Action) => this.activityActionItems[action.id],
140 141
			orientation: ActionsOrientation.VERTICAL,
			ariaLabel: nls.localize('activityBarAriaLabel', "Active View Switcher")
E
Erich Gamma 已提交
142 143
		});

P
Pine Wu 已提交
144 145 146 147
		// Load stock viewlets
		const allViewlets = (<ViewletRegistry>Registry.as(ViewletExtensions.Viewlets)).getViewlets().filter(v => !v.isExternal);
		this.fillViewletSwitcher(allViewlets);
	}
J
Joao Moreno 已提交
148

P
Pine Wu 已提交
149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165
	private refreshViewletSwitcher(): void {
		this.viewletSwitcherBar.clear();

		// Load stock viewlets + enabled external viewlets
		const allEnabledViewlets = (<ViewletRegistry>Registry.as(ViewletExtensions.Viewlets)).getViewlets().filter(descriptor => {
			if (!descriptor.isExternal) {
				return true;
			} else {
				return this.viewletsToggleStatus[descriptor.id];
			}
		});
		this.fillViewletSwitcher(allEnabledViewlets);
	}

	private fillViewletSwitcher(viewlets: ViewletDescriptor[]) {
		// Build Viewlet Actions in correct order
		const viewletActions = viewlets.sort((v1, v2) => v1.order - v2.order).map(v => this.toAction(v));
I
isidor 已提交
166 167
		this.viewletSwitcherBar.push(viewletActions, { label: true, icon: true });
	}
J
Joao Moreno 已提交
168

I
isidor 已提交
169 170
	private toAction(composite: ViewletDescriptor): ActivityAction {
		const action = this.instantiationService.createInstance(ViewletActivityAction, composite.id + '.activity-bar-action', composite);
I
isidor 已提交
171

172
		this.activityActionItems[action.id] = new ActivityActionItem(action, composite.name, this.getKeybindingLabel(composite.id));
I
isidor 已提交
173 174 175 176 177
		this.compositeIdToActions[composite.id] = action;

		return action;
	};

178 179 180 181 182 183 184 185 186
	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 已提交
187
	public dispose(): void {
I
isidor 已提交
188 189 190 191 192
		if (this.viewletSwitcherBar) {
			this.viewletSwitcherBar.dispose();
			this.viewletSwitcherBar = null;
		}

E
Erich Gamma 已提交
193 194 195 196
		super.dispose();
	}
}

197
class ViewletActivityAction extends ActivityAction {
E
Erich Gamma 已提交
198
	private static preventDoubleClickDelay = 300;
199
	private lastRun: number = 0;
E
Erich Gamma 已提交
200 201

	constructor(
202 203 204
		id: string, private viewlet: ViewletDescriptor,
		@IViewletService private viewletService: IViewletService,
		@IPartService private partService: IPartService
E
Erich Gamma 已提交
205
	) {
206
		super(id, viewlet.name, viewlet.cssClass);
E
Erich Gamma 已提交
207 208
	}

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

211
		// prevent accident trigger on a doubleclick (to help nervous people)
212
		const now = Date.now();
213
		if (now - this.lastRun < ViewletActivityAction.preventDoubleClickDelay) {
A
Alex Dima 已提交
214
			return TPromise.as(true);
E
Erich Gamma 已提交
215
		}
216
		this.lastRun = now;
E
Erich Gamma 已提交
217

I
isidor 已提交
218 219
		const sideBarHidden = this.partService.isSideBarHidden();
		const activeViewlet = this.viewletService.getActiveViewlet();
E
Erich Gamma 已提交
220 221

		// Hide sidebar if selected viewlet already visible
222
		if (!sideBarHidden && activeViewlet && activeViewlet.getId() === this.viewlet.id) {
E
Erich Gamma 已提交
223
			this.partService.setSideBarHidden(true);
I
isidor 已提交
224
		} else {
225
			this.viewletService.openViewlet(this.viewlet.id, true).done(null, errors.onUnexpectedError);
I
isidor 已提交
226
			this.activate();
E
Erich Gamma 已提交
227
		}
228 229

		return TPromise.as(true);
I
isidor 已提交
230 231
	}
}