activitybarPart.ts 9.3 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');
10
import { TPromise } from 'vs/base/common/winjs.base';
J
Johannes Rieken 已提交
11
import { illegalArgument } from 'vs/base/common/errors';
12
import { Builder, $, Dimension } from 'vs/base/browser/builder';
J
Johannes Rieken 已提交
13
import { Action } from 'vs/base/common/actions';
14
import { ActionsOrientation, ActionBar, Separator } from 'vs/base/browser/ui/actionbar/actionbar';
B
Benjamin Pasero 已提交
15
import { GlobalActivityExtensions, IGlobalActivityRegistry } from 'vs/workbench/common/activity';
16
import { Registry } from 'vs/platform/registry/common/platform';
J
Johannes Rieken 已提交
17
import { Part } from 'vs/workbench/browser/part';
18
import { GlobalActivityActionItem, GlobalActivityAction, ViewletActivityAction, ToggleViewletAction } from 'vs/workbench/browser/parts/activitybar/activitybarActions';
B
Benjamin Pasero 已提交
19
import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet';
20
import { IActivityBarService, IBadge } from 'vs/workbench/services/activity/common/activityBarService';
21
import { IPartService, Position as SideBarPosition } from 'vs/workbench/services/part/common/partService';
J
Johannes Rieken 已提交
22
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
23
import { IExtensionService } from 'vs/platform/extensions/common/extensions';
24 25 26
import { IStorageService } from 'vs/platform/storage/common/storage';
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
import { StandardMouseEvent } from 'vs/base/browser/mouseEvent';
J
Joao Moreno 已提交
27
import { dispose, IDisposable, toDisposable } from 'vs/base/common/lifecycle';
28
import { ToggleActivityBarVisibilityAction } from 'vs/workbench/browser/actions/toggleActivityBarVisibility';
29
import { IThemeService } from 'vs/platform/theme/common/themeService';
I
isidor 已提交
30
import { ACTIVITY_BAR_BACKGROUND, ACTIVITY_BAR_BORDER, ACTIVITY_BAR_FOREGROUND } from 'vs/workbench/common/theme';
31
import { contrastBorder } from 'vs/platform/theme/common/colorRegistry';
32
import { CompositeBar } from 'vs/workbench/browser/parts/compositebar/compositeBar';
33
import { ToggleCompositePinnedAction } from 'vs/workbench/browser/parts/compositebar/compositeBarActions';
E
Erich Gamma 已提交
34

35
export class ActivitybarPart extends Part implements IActivityBarService {
36

37
	private static readonly PINNED_VIEWLETS = 'workbench.activity.pinnedViewlets';
38

39
	public _serviceBrand: any;
P
Pine Wu 已提交
40

41 42
	private dimension: Dimension;

43 44 45
	private globalActionBar: ActionBar;
	private globalActivityIdToActions: { [globalActivityId: string]: GlobalActivityAction; };

46
	private compositeBar: CompositeBar;
47

E
Erich Gamma 已提交
48
	constructor(
49 50
		id: string,
		@IViewletService private viewletService: IViewletService,
51
		@IExtensionService private extensionService: IExtensionService,
52 53
		@IStorageService private storageService: IStorageService,
		@IContextMenuService private contextMenuService: IContextMenuService,
I
isidor 已提交
54
		@IInstantiationService private instantiationService: IInstantiationService,
B
Benjamin Pasero 已提交
55 56
		@IPartService private partService: IPartService,
		@IThemeService themeService: IThemeService
E
Erich Gamma 已提交
57
	) {
B
Benjamin Pasero 已提交
58
		super(id, { hasTitle: false }, themeService);
E
Erich Gamma 已提交
59

J
Joao Moreno 已提交
60
		this.globalActivityIdToActions = Object.create(null);
61
		this.compositeBar = this.instantiationService.createInstance(CompositeBar, {
I
isidor 已提交
62
			icon: true,
63 64 65
			storageId: ActivitybarPart.PINNED_VIEWLETS,
			orientation: ActionsOrientation.VERTICAL,
			composites: this.viewletService.getViewlets(),
66
			openComposite: (compositeId: string) => this.viewletService.openViewlet(compositeId, true),
67
			getActivityAction: (compositeId: string) => this.instantiationService.createInstance(ViewletActivityAction, this.viewletService.getViewlet(compositeId)),
68
			getCompositePinnedAction: (compositeId: string) => new ToggleCompositePinnedAction(this.viewletService.getViewlet(compositeId), this.compositeBar),
69 70
			getOnCompositeClickAction: (compositeId: string) => this.instantiationService.createInstance(ToggleViewletAction, this.viewletService.getViewlet(compositeId)),
			getDefaultCompositeId: () => this.viewletService.getDefaultViewletId(),
I
isidor 已提交
71 72
			hidePart: () => this.partService.setSideBarHidden(true),
			backgroundColor: ACTIVITY_BAR_FOREGROUND
73
		});
E
Erich Gamma 已提交
74 75 76 77 78 79
		this.registerListeners();
	}

	private registerListeners(): void {

		// Activate viewlet action on opening of a viewlet
80
		this.toUnbind.push(this.viewletService.onDidViewletOpen(viewlet => this.compositeBar.activateComposite(viewlet.getId())));
E
Erich Gamma 已提交
81 82

		// Deactivate viewlet action on close
83 84
		this.toUnbind.push(this.viewletService.onDidViewletClose(viewlet => this.compositeBar.deactivateComposite(viewlet.getId())));
		this.toUnbind.push(this.compositeBar.onDidContextMenu(e => this.showContextMenu(e)));
E
Erich Gamma 已提交
85 86
	}

B
Benjamin Pasero 已提交
87 88
	public showActivity(viewletOrActionId: string, badge: IBadge, clazz?: string): IDisposable {
		if (this.viewletService.getViewlet(viewletOrActionId)) {
89
			return this.compositeBar.showActivity(viewletOrActionId, badge, clazz);
B
Benjamin Pasero 已提交
90 91 92 93 94 95
		}

		return this.showGlobalActivity(viewletOrActionId, badge);
	}

	private showGlobalActivity(globalActivityId: string, badge: IBadge): IDisposable {
J
Joao Moreno 已提交
96 97 98 99 100 101 102 103 104 105
		if (!badge) {
			throw illegalArgument('badge');
		}

		const action = this.globalActivityIdToActions[globalActivityId];
		if (!action) {
			throw illegalArgument('globalActivityId');
		}

		action.setBadge(badge);
B
Benjamin Pasero 已提交
106

J
Joao Moreno 已提交
107 108 109
		return toDisposable(() => action.setBadge(undefined));
	}

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

		// Top Actionbar with action items for each viewlet action
I
isidor 已提交
115
		this.compositeBar.create($result.getHTMLElement());
E
Erich Gamma 已提交
116

117
		// Top Actionbar with action items for each viewlet action
I
isidor 已提交
118
		this.createGlobalActivityActionBar($('.global-activity').appendTo($result).getHTMLElement());
119

E
Erich Gamma 已提交
120 121 122
		return $result;
	}

123 124 125 126 127
	public updateStyles(): void {
		super.updateStyles();

		// Part container
		const container = this.getContainer();
128 129
		const background = this.getColor(ACTIVITY_BAR_BACKGROUND);
		container.style('background-color', background);
130

131
		const borderColor = this.getColor(ACTIVITY_BAR_BORDER) || this.getColor(contrastBorder);
132
		const isPositionLeft = this.partService.getSideBarPosition() === SideBarPosition.LEFT;
133 134 135 136 137 138 139
		container.style('box-sizing', borderColor && isPositionLeft ? 'border-box' : null);
		container.style('border-right-width', borderColor && isPositionLeft ? '1px' : null);
		container.style('border-right-style', borderColor && isPositionLeft ? 'solid' : null);
		container.style('border-right-color', isPositionLeft ? borderColor : null);
		container.style('border-left-width', borderColor && !isPositionLeft ? '1px' : null);
		container.style('border-left-style', borderColor && !isPositionLeft ? 'solid' : null);
		container.style('border-left-color', !isPositionLeft ? borderColor : null);
140 141
	}

142 143 144
	private showContextMenu(e: MouseEvent): void {
		const event = new StandardMouseEvent(e);

145
		const actions: Action[] = this.viewletService.getViewlets().map(viewlet => this.instantiationService.createInstance(ToggleCompositePinnedAction, viewlet, this.compositeBar));
146 147 148 149
		actions.push(new Separator());
		actions.push(this.instantiationService.createInstance(ToggleActivityBarVisibilityAction, ToggleActivityBarVisibilityAction.ID, nls.localize('hideActivitBar', "Hide Activity Bar")));

		this.contextMenuService.showContextMenu({
B
Benjamin Pasero 已提交
150
			getAnchor: () => { return { x: event.posx, y: event.posy }; },
151 152 153 154 155
			getActions: () => TPromise.as(actions),
			onHide: () => dispose(actions)
		});
	}

J
Joao Moreno 已提交
156
	private createGlobalActivityActionBar(container: HTMLElement): void {
J
Joao Moreno 已提交
157
		const activityRegistry = Registry.as<IGlobalActivityRegistry>(GlobalActivityExtensions);
158 159 160 161 162
		const descriptors = activityRegistry.getActivities();
		const actions = descriptors
			.map(d => this.instantiationService.createInstance(d))
			.map(a => new GlobalActivityAction(a));

163
		this.globalActionBar = new ActionBar(container, {
164 165 166 167 168 169
			actionItemProvider: a => this.instantiationService.createInstance(GlobalActivityActionItem, a),
			orientation: ActionsOrientation.VERTICAL,
			ariaLabel: nls.localize('globalActions', "Global Actions"),
			animated: false
		});

J
Joao Moreno 已提交
170 171
		actions.forEach(a => {
			this.globalActivityIdToActions[a.id] = a;
172
			this.globalActionBar.push(a);
J
Joao Moreno 已提交
173
		});
174 175
	}

176
	public getPinned(): string[] {
177
		return this.viewletService.getViewlets().map(v => v.id).filter(id => this.compositeBar.isPinned(id));;
178 179
	}

180 181 182 183 184 185 186 187 188 189
	/**
	 * Layout title, content and status area in the given dimension.
	 */
	public layout(dimension: Dimension): Dimension[] {

		// Pass to super
		const sizes = super.layout(dimension);

		this.dimension = sizes[1];

190 191 192
		let availableHeight = this.dimension.height;
		if (this.globalActionBar) {
			// adjust height for global actions showing
193
			availableHeight -= (this.globalActionBar.items.length * this.globalActionBar.domNode.clientHeight);
194 195
		}
		this.compositeBar.layout(new Dimension(dimension.width, availableHeight));
196 197 198

		return sizes;
	}
I
isidor 已提交
199

E
Erich Gamma 已提交
200
	public dispose(): void {
201 202 203
		if (this.compositeBar) {
			this.compositeBar.dispose();
			this.compositeBar = null;
I
isidor 已提交
204 205
		}

B
Benjamin Pasero 已提交
206 207 208 209 210
		if (this.globalActionBar) {
			this.globalActionBar.dispose();
			this.globalActionBar = null;
		}

E
Erich Gamma 已提交
211 212
		super.dispose();
	}
213 214 215

	public shutdown(): void {
		// Persist Hidden State
216
		this.compositeBar.store();
217 218 219 220

		// Pass to super
		super.shutdown();
	}
221
}