composite.ts 8.3 KB
Newer Older
1 2 3 4 5
/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/

J
Johannes Rieken 已提交
6 7 8 9
import { TPromise } from 'vs/base/common/winjs.base';
import { Dimension, Builder } from 'vs/base/browser/builder';
import { IAction, IActionRunner, ActionRunner } from 'vs/base/common/actions';
import { IActionItem } from 'vs/base/browser/ui/actionbar/actionbar';
B
Benjamin Pasero 已提交
10
import { Component } from 'vs/workbench/common/component';
J
Johannes Rieken 已提交
11 12 13 14
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { IComposite } from 'vs/workbench/common/composite';
import { IEditorControl } from 'vs/platform/editor/common/editor';
import Event, { Emitter } from 'vs/base/common/event';
15
import { IThemeService } from 'vs/platform/theme/common/themeService';
16
import { IConstructorSignature0, IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
M
Matt Bierner 已提交
17 18
import DOM = require('vs/base/browser/dom');
import { IDisposable } from 'vs/base/common/lifecycle';
19 20

/**
I
isidor 已提交
21 22 23
 * Composites are layed out in the sidebar and panel part of the workbench. At a time only one composite
 * can be open in the sidebar, and only one composite can be open in the panel.
 * Each composite has a minimized representation that is good enough to provide some
24 25 26 27 28 29
 * information about the state of the composite data.
 * The workbench will keep a composite alive after it has been created and show/hide it based on
 * user interaction. The lifecycle of a composite goes in the order create(), setVisible(true|false),
 * layout(), focus(), dispose(). During use of the workbench, a composite will often receive a setVisible,
 * layout and focus call, but only one create and dispose call.
 */
B
Benjamin Pasero 已提交
30
export abstract class Composite extends Component implements IComposite {
M
Matt Bierner 已提交
31 32
	private readonly _onTitleAreaUpdate: Emitter<void>;
	private readonly _onDidFocus: Emitter<void>;
M
Matt Bierner 已提交
33 34 35

	private _focusTracker?: DOM.IFocusTracker;
	private _focusListenerDisposable?: IDisposable;
36

37 38 39 40 41 42 43 44
	private visible: boolean;
	private parent: Builder;

	protected actionRunner: IActionRunner;

	/**
	 * Create a new composite with the given ID and context.
	 */
45 46 47
	constructor(
		id: string,
		private _telemetryService: ITelemetryService,
B
Benjamin Pasero 已提交
48
		themeService: IThemeService
49 50
	) {
		super(id, themeService);
51 52

		this.visible = false;
53
		this._onTitleAreaUpdate = new Emitter<void>();
M
Matt Bierner 已提交
54
		this._onDidFocus = new Emitter<void>();
55 56 57 58 59 60
	}

	public getTitle(): string {
		return null;
	}

B
Benjamin Pasero 已提交
61
	protected get telemetryService(): ITelemetryService {
62 63 64
		return this._telemetryService;
	}

65 66 67 68
	public get onTitleAreaUpdate(): Event<void> {
		return this._onTitleAreaUpdate.event;
	}

69
	/**
B
Benjamin Pasero 已提交
70
	 * Note: Clients should not call this method, the workbench calls this
71 72 73 74 75 76 77 78 79 80
	 * method. Calling it otherwise may result in unexpected behavior.
	 *
	 * Called to create this composite on the provided builder. This method is only
	 * called once during the lifetime of the workbench.
	 * Note that DOM-dependent calculations should be performed from the setVisible()
	 * call. Only then the composite will be part of the DOM.
	 */
	public create(parent: Builder): TPromise<void> {
		this.parent = parent;

A
Alex Dima 已提交
81
		return TPromise.as(null);
82 83
	}

B
Benjamin Pasero 已提交
84 85 86 87
	public updateStyles(): void {
		super.updateStyles();
	}

88 89 90 91 92 93 94
	/**
	 * Returns the container this composite is being build in.
	 */
	public getContainer(): Builder {
		return this.parent;
	}

M
Matt Bierner 已提交
95 96 97 98 99 100
	public get onDidFocus(): Event<any> {
		this._focusTracker = DOM.trackFocus(this.getContainer().getHTMLElement());
		this._focusListenerDisposable = this._focusTracker.onDidFocus(() => {
			this._onDidFocus.fire();
		});
		return this._onDidFocus.event;
M
Matt Bierner 已提交
101 102
	}

103
	/**
B
Benjamin Pasero 已提交
104
	 * Note: Clients should not call this method, the workbench calls this
105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147
	 * method. Calling it otherwise may result in unexpected behavior.
	 *
	 * Called to indicate that the composite has become visible or hidden. This method
	 * is called more than once during workbench lifecycle depending on the user interaction.
	 * The composite will be on-DOM if visible is set to true and off-DOM otherwise.
	 *
	 * The returned promise is complete when the composite is visible. As such it is valid
	 * to do a long running operation from this call. Typically this operation should be
	 * fast though because setVisible might be called many times during a session.
	 */
	public setVisible(visible: boolean): TPromise<void> {
		this.visible = visible;

		return TPromise.as(null);
	}

	/**
	 * Called when this composite should receive keyboard focus.
	 */
	public focus(): void {
		// Subclasses can implement
	}

	/**
	 * Layout the contents of this composite using the provided dimensions.
	 */
	public abstract layout(dimension: Dimension): void;

	/**
	 * Returns an array of actions to show in the action bar of the composite.
	 */
	public getActions(): IAction[] {
		return [];
	}

	/**
	 * Returns an array of actions to show in the action bar of the composite
	 * in a less prominent way then action from getActions.
	 */
	public getSecondaryActions(): IAction[] {
		return [];
	}

148 149 150 151 152 153 154
	/**
	 * Returns an array of actions to show in the context menu of the composite
	 */
	public getContextMenuActions(): IAction[] {
		return [];
	}

155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183
	/**
	 * For any of the actions returned by this composite, provide an IActionItem in
	 * cases where the implementor of the composite wants to override the presentation
	 * of an action. Returns null to indicate that the action is not rendered through
	 * an action item.
	 */
	public getActionItem(action: IAction): IActionItem {
		return null;
	}

	/**
	 * Returns the instance of IActionRunner to use with this composite for the
	 * composite tool bar.
	 */
	public getActionRunner(): IActionRunner {
		if (!this.actionRunner) {
			this.actionRunner = new ActionRunner();
		}

		return this.actionRunner;
	}

	/**
	 * Method for composite implementors to indicate to the composite container that the title or the actions
	 * of the composite have changed. Calling this method will cause the container to ask for title (getTitle())
	 * and actions (getActions(), getSecondaryActions()) if the composite is visible or the next time the composite
	 * gets visible.
	 */
	protected updateTitleArea(): void {
184
		this._onTitleAreaUpdate.fire();
185 186 187 188 189 190 191 192 193 194 195 196
	}

	/**
	 * Returns true if this composite is currently visible and false otherwise.
	 */
	public isVisible(): boolean {
		return this.visible;
	}

	/**
	 * Returns the underlying composite control or null if it is not accessible.
	 */
A
Alex Dima 已提交
197
	public getControl(): IEditorControl {
198 199
		return null;
	}
200 201 202

	public dispose(): void {
		this._onTitleAreaUpdate.dispose();
M
Matt Bierner 已提交
203 204 205 206 207 208 209 210 211
		this._onDidFocus.dispose();

		if (this._focusTracker) {
			this._focusTracker.dispose();
		}

		if (this._focusListenerDisposable) {
			this._focusListenerDisposable.dispose();
		}
212 213 214

		super.dispose();
	}
215
}
I
isidor 已提交
216 217

/**
B
Benjamin Pasero 已提交
218
 * A composite descriptor is a leightweight descriptor of a composite in the workbench.
I
isidor 已提交
219
 */
220
export abstract class CompositeDescriptor<T extends Composite> {
I
isidor 已提交
221 222 223 224
	public id: string;
	public name: string;
	public cssClass: string;
	public order: number;
M
Matt Bierner 已提交
225
	public keybindingId: string;
226
	public enabled: boolean;
I
isidor 已提交
227

228
	private ctor: IConstructorSignature0<T>;
I
isidor 已提交
229

I
isidor 已提交
230
	constructor(ctor: IConstructorSignature0<T>, id: string, name: string, cssClass?: string, order?: number, keybindingId?: string, ) {
231
		this.ctor = ctor;
I
isidor 已提交
232 233 234 235
		this.id = id;
		this.name = name;
		this.cssClass = cssClass;
		this.order = order;
236
		this.enabled = true;
I
isidor 已提交
237
		this.keybindingId = keybindingId;
I
isidor 已提交
238
	}
239 240 241 242

	public instantiate(instantiationService: IInstantiationService): T {
		return instantiationService.createInstance(this.ctor);
	}
I
isidor 已提交
243
}
I
isidor 已提交
244

245
export abstract class CompositeRegistry<T extends Composite> {
B
Benjamin Pasero 已提交
246
	private composites: CompositeDescriptor<T>[];
I
isidor 已提交
247 248

	constructor() {
B
Benjamin Pasero 已提交
249
		this.composites = [];
I
isidor 已提交
250 251 252
	}

	protected registerComposite(descriptor: CompositeDescriptor<T>): void {
I
isidor 已提交
253
		if (this.compositeById(descriptor.id) !== null) {
I
isidor 已提交
254 255 256
			return;
		}

B
Benjamin Pasero 已提交
257
		this.composites.push(descriptor);
I
isidor 已提交
258 259
	}

260
	public getComposite(id: string): CompositeDescriptor<T> {
I
isidor 已提交
261
		return this.compositeById(id);
I
isidor 已提交
262 263
	}

B
Benjamin Pasero 已提交
264 265
	protected getComposites(): CompositeDescriptor<T>[] {
		return this.composites.slice(0);
I
isidor 已提交
266 267
	}

I
isidor 已提交
268
	private compositeById(id: string): CompositeDescriptor<T> {
B
Benjamin Pasero 已提交
269 270 271
		for (let i = 0; i < this.composites.length; i++) {
			if (this.composites[i].id === id) {
				return this.composites[i];
I
isidor 已提交
272 273 274 275 276
			}
		}

		return null;
	}
277
}