views.ts 11.5 KB
Newer Older
S
Sandeep Somavarapu 已提交
1 2 3 4 5 6
/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/

import { Command } from 'vs/editor/common/modes';
S
Sandeep Somavarapu 已提交
7
import { UriComponents } from 'vs/base/common/uri';
M
Matt Bierner 已提交
8
import { Event, Emitter } from 'vs/base/common/event';
S
Sandeep Somavarapu 已提交
9 10 11 12
import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
import { ITreeViewDataProvider } from 'vs/workbench/common/views';
import { localize } from 'vs/nls';
import { IViewlet } from 'vs/workbench/common/viewlet';
S
Sandeep Somavarapu 已提交
13
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
14
import { IDisposable } from 'vs/base/common/lifecycle';
S
Sandeep Somavarapu 已提交
15
import { ThemeIcon } from 'vs/platform/theme/common/themeService';
S
Sandeep Somavarapu 已提交
16
import { values, keys } from 'vs/base/common/map';
S
Sandeep Somavarapu 已提交
17
import { Registry } from 'vs/platform/registry/common/platform';
S
Sandeep Somavarapu 已提交
18
import { IKeybindings } from 'vs/platform/keybinding/common/keybindingsRegistry';
19
import { IAction } from 'vs/base/common/actions';
20
import { IMarkdownString } from 'vs/base/common/htmlContent';
21
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
S
Sandeep Somavarapu 已提交
22

23
export const TEST_VIEW_CONTAINER_ID = 'workbench.view.extension.test';
S
Sandeep Somavarapu 已提交
24

S
Sandeep Somavarapu 已提交
25 26 27
export namespace Extensions {
	export const ViewContainersRegistry = 'workbench.registry.view.containers';
}
S
Sandeep Somavarapu 已提交
28

S
Sandeep Somavarapu 已提交
29 30 31 32 33 34
export interface IViewContainersRegistry {
	/**
	 * An event that is triggerred when a view container is registered.
	 */
	readonly onDidRegister: Event<ViewContainer>;

S
Sandeep Somavarapu 已提交
35 36 37 38 39
	/**
	 * An event that is triggerred when a view container is deregistered.
	 */
	readonly onDidDeregister: Event<ViewContainer>;

S
Sandeep Somavarapu 已提交
40 41 42 43 44 45 46 47 48 49 50 51 52
	/**
	 * All registered view containers
	 */
	readonly all: ViewContainer[];

	/**
	 * Registers a view container with given id
	 * No op if a view container is already registered with the given id.
	 *
	 * @param id of the view container.
	 *
	 * @returns the registered ViewContainer.
	 */
53
	registerViewContainer(id: string, extensionId?: ExtensionIdentifier): ViewContainer;
S
Sandeep Somavarapu 已提交
54

S
Sandeep Somavarapu 已提交
55 56 57 58 59 60
	/**
	 * Deregisters the given view container
	 * No op if the view container is not registered
	 */
	deregisterViewContainer(viewContainer: ViewContainer): void;

S
Sandeep Somavarapu 已提交
61 62 63 64 65
	/**
	 * Returns the view container with given id.
	 *
	 * @returns the view container with given id.
	 */
66
	get(id: string): ViewContainer | undefined;
S
Sandeep Somavarapu 已提交
67
}
68

S
Sandeep Somavarapu 已提交
69
export class ViewContainer {
70
	protected constructor(readonly id: string, readonly extensionId: ExtensionIdentifier) { }
S
Sandeep Somavarapu 已提交
71 72 73 74
}

class ViewContainersRegistryImpl implements IViewContainersRegistry {

75
	private readonly _onDidRegister = new Emitter<ViewContainer>();
S
Sandeep Somavarapu 已提交
76
	readonly onDidRegister: Event<ViewContainer> = this._onDidRegister.event;
77

S
Sandeep Somavarapu 已提交
78 79 80
	private readonly _onDidDeregister = new Emitter<ViewContainer>();
	readonly onDidDeregister: Event<ViewContainer> = this._onDidDeregister.event;

S
Sandeep Somavarapu 已提交
81 82 83 84 85 86
	private viewContainers: Map<string, ViewContainer> = new Map<string, ViewContainer>();

	get all(): ViewContainer[] {
		return values(this.viewContainers);
	}

87
	registerViewContainer(id: string, extensionId: ExtensionIdentifier): ViewContainer {
88 89 90
		const existing = this.viewContainers.get(id);
		if (existing) {
			return existing;
S
Sandeep Somavarapu 已提交
91
		}
92 93 94 95 96 97 98 99 100

		const viewContainer = new class extends ViewContainer {
			constructor() {
				super(id, extensionId);
			}
		};
		this.viewContainers.set(id, viewContainer);
		this._onDidRegister.fire(viewContainer);
		return viewContainer;
S
Sandeep Somavarapu 已提交
101 102
	}

S
Sandeep Somavarapu 已提交
103 104 105 106 107 108 109 110
	deregisterViewContainer(viewContainer: ViewContainer): void {
		const existing = this.viewContainers.get(viewContainer.id);
		if (existing) {
			this.viewContainers.delete(viewContainer.id);
			this._onDidDeregister.fire(viewContainer);
		}
	}

111
	get(id: string): ViewContainer | undefined {
S
Sandeep Somavarapu 已提交
112 113
		return this.viewContainers.get(id);
	}
S
Sandeep Somavarapu 已提交
114 115
}

S
Sandeep Somavarapu 已提交
116 117
Registry.add(Extensions.ViewContainersRegistry, new ViewContainersRegistryImpl());

S
Sandeep Somavarapu 已提交
118 119 120 121 122 123
export interface IViewDescriptor {

	readonly id: string;

	readonly name: string;

B
Benjamin Pasero 已提交
124
	// TODO@Sandeep do we really need this?!
S
Sandeep Somavarapu 已提交
125 126 127 128 129 130 131 132 133 134 135
	readonly ctor: any;

	readonly when?: ContextKeyExpr;

	readonly order?: number;

	readonly weight?: number;

	readonly collapsed?: boolean;

	readonly canToggleVisibility?: boolean;
136

137
	// Applies only to newly created views
138
	readonly hideByDefault?: boolean;
S
Sandeep Somavarapu 已提交
139 140

	readonly focusCommand?: { id: string, keybindings?: IKeybindings };
S
Sandeep Somavarapu 已提交
141 142
}

S
Sandeep Somavarapu 已提交
143
export interface IViewDescriptorCollection extends IDisposable {
S
Sandeep Somavarapu 已提交
144 145
	readonly onDidChangeActiveViews: Event<{ added: IViewDescriptor[], removed: IViewDescriptor[] }>;
	readonly activeViewDescriptors: IViewDescriptor[];
S
Sandeep Somavarapu 已提交
146
	readonly allViewDescriptors: IViewDescriptor[];
147 148
}

S
Sandeep Somavarapu 已提交
149 150
export interface IViewsRegistry {

151
	readonly onViewsRegistered: Event<{ views: IViewDescriptor[], viewContainer: ViewContainer }>;
S
Sandeep Somavarapu 已提交
152

153
	readonly onViewsDeregistered: Event<{ views: IViewDescriptor[], viewContainer: ViewContainer }>;
S
Sandeep Somavarapu 已提交
154

155 156
	readonly onDidChangeContainer: Event<{ views: IViewDescriptor[], from: ViewContainer, to: ViewContainer }>;

157
	registerViews(views: IViewDescriptor[], viewContainer: ViewContainer): void;
S
Sandeep Somavarapu 已提交
158

S
Sandeep Somavarapu 已提交
159
	deregisterViews(views: IViewDescriptor[], viewContainer: ViewContainer): void;
S
Sandeep Somavarapu 已提交
160

S
Sandeep Somavarapu 已提交
161
	moveViews(views: IViewDescriptor[], viewContainer: ViewContainer): void;
162

163
	getViews(viewContainer: ViewContainer): IViewDescriptor[];
S
Sandeep Somavarapu 已提交
164

M
Matt Bierner 已提交
165
	getView(id: string): IViewDescriptor | null;
S
Sandeep Somavarapu 已提交
166

167
	getViewContainer(id: string): ViewContainer | null;
S
Sandeep Somavarapu 已提交
168 169 170 171
}

export const ViewsRegistry: IViewsRegistry = new class implements IViewsRegistry {

172 173
	private readonly _onViewsRegistered: Emitter<{ views: IViewDescriptor[], viewContainer: ViewContainer }> = new Emitter<{ views: IViewDescriptor[], viewContainer: ViewContainer }>();
	readonly onViewsRegistered: Event<{ views: IViewDescriptor[], viewContainer: ViewContainer }> = this._onViewsRegistered.event;
S
Sandeep Somavarapu 已提交
174

175 176
	private readonly _onViewsDeregistered: Emitter<{ views: IViewDescriptor[], viewContainer: ViewContainer }> = new Emitter<{ views: IViewDescriptor[], viewContainer: ViewContainer }>();
	readonly onViewsDeregistered: Event<{ views: IViewDescriptor[], viewContainer: ViewContainer }> = this._onViewsDeregistered.event;
S
Sandeep Somavarapu 已提交
177

178 179 180
	private readonly _onDidChangeContainer: Emitter<{ views: IViewDescriptor[], from: ViewContainer, to: ViewContainer }> = new Emitter<{ views: IViewDescriptor[], from: ViewContainer, to: ViewContainer }>();
	readonly onDidChangeContainer: Event<{ views: IViewDescriptor[], from: ViewContainer, to: ViewContainer }> = this._onDidChangeContainer.event;

181
	private _viewContainers: ViewContainer[] = [];
S
Sandeep Somavarapu 已提交
182
	private _views: Map<ViewContainer, IViewDescriptor[]> = new Map<ViewContainer, IViewDescriptor[]>();
S
Sandeep Somavarapu 已提交
183

S
Sandeep Somavarapu 已提交
184 185 186
	registerViews(views: IViewDescriptor[], viewContainer: ViewContainer): void {
		this.addViews(views, viewContainer);
		this._onViewsRegistered.fire({ views: views, viewContainer });
S
Sandeep Somavarapu 已提交
187 188
	}

S
Sandeep Somavarapu 已提交
189 190 191 192
	deregisterViews(viewDescriptors: IViewDescriptor[], viewContainer: ViewContainer): void {
		const views = this.removeViews(viewDescriptors, viewContainer);
		if (views.length) {
			this._onViewsDeregistered.fire({ views, viewContainer });
S
Sandeep Somavarapu 已提交
193 194 195
		}
	}

S
Sandeep Somavarapu 已提交
196 197
	moveViews(viewsToMove: IViewDescriptor[], viewContainer: ViewContainer): void {
		keys(this._views).forEach(container => {
198
			if (container !== viewContainer) {
S
Sandeep Somavarapu 已提交
199 200 201 202
				const views = this.removeViews(viewsToMove, container);
				if (views.length) {
					this.addViews(views, viewContainer);
					this._onDidChangeContainer.fire({ views, from: container, to: viewContainer });
203 204 205 206 207
				}
			}
		});
	}

S
Sandeep Somavarapu 已提交
208
	getViews(loc: ViewContainer): IViewDescriptor[] {
S
Sandeep Somavarapu 已提交
209 210 211
		return this._views.get(loc) || [];
	}

M
Matt Bierner 已提交
212
	getView(id: string): IViewDescriptor | null {
213
		for (const viewContainer of this._viewContainers) {
S
Sandeep Somavarapu 已提交
214
			const viewDescriptor = (this._views.get(viewContainer) || []).filter(v => v.id === id)[0];
S
Sandeep Somavarapu 已提交
215 216 217 218 219
			if (viewDescriptor) {
				return viewDescriptor;
			}
		}
		return null;
S
Sandeep Somavarapu 已提交
220
	}
S
Sandeep Somavarapu 已提交
221

222 223 224 225 226 227 228 229
	getViewContainer(viewId: string): ViewContainer | null {
		for (const viewContainer of this._viewContainers) {
			const viewDescriptor = (this._views.get(viewContainer) || []).filter(v => v.id === viewId)[0];
			if (viewDescriptor) {
				return viewContainer;
			}
		}
		return null;
S
Sandeep Somavarapu 已提交
230
	}
S
Sandeep Somavarapu 已提交
231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270

	private addViews(viewDescriptors: IViewDescriptor[], viewContainer: ViewContainer): void {
		let views = this._views.get(viewContainer);
		if (!views) {
			views = [];
			this._views.set(viewContainer, views);
			this._viewContainers.push(viewContainer);
		}
		for (const viewDescriptor of viewDescriptors) {
			if (views.some(v => v.id === viewDescriptor.id)) {
				throw new Error(localize('duplicateId', "A view with id '{0}' is already registered in the container '{1}'", viewDescriptor.id, viewContainer.id));
			}
			views.push(viewDescriptor);
		}
	}

	private removeViews(viewDescriptors: IViewDescriptor[], viewContainer: ViewContainer): IViewDescriptor[] {
		const views = this._views.get(viewContainer);
		if (!views) {
			return [];
		}
		const viewsToDeregister: IViewDescriptor[] = [];
		const remaningViews: IViewDescriptor[] = [];
		for (const view of views) {
			if (viewDescriptors.indexOf(view) === -1) {
				remaningViews.push(view);
			} else {
				viewsToDeregister.push(view);
			}
		}
		if (viewsToDeregister.length) {
			if (remaningViews.length) {
				this._views.set(viewContainer, remaningViews);
			} else {
				this._views.delete(viewContainer);
				this._viewContainers.splice(this._viewContainers.indexOf(viewContainer), 1);
			}
		}
		return viewsToDeregister;
	}
S
Sandeep Somavarapu 已提交
271 272
};

S
Sandeep Somavarapu 已提交
273 274 275 276 277 278
export interface IView {

	readonly id: string;

}

S
Sandeep Somavarapu 已提交
279 280
export interface IViewsViewlet extends IViewlet {

I
isidor 已提交
281
	openView(id: string, focus?: boolean): IView;
S
Sandeep Somavarapu 已提交
282 283 284

}

285 286 287 288 289
export const IViewsService = createDecorator<IViewsService>('viewsService');

export interface IViewsService {
	_serviceBrand: any;

M
Matt Bierner 已提交
290
	openView(id: string, focus?: boolean): Promise<IView | null>;
291 292

	getViewDescriptors(container: ViewContainer): IViewDescriptorCollection;
293 294
}

S
Sandeep Somavarapu 已提交
295 296
// Custom views

S
rename  
Sandeep Somavarapu 已提交
297
export interface ITreeView extends IDisposable {
298

299
	dataProvider: ITreeViewDataProvider;
S
Sandeep Somavarapu 已提交
300

301 302
	showCollapseAllAction: boolean;

303 304
	message: string | IMarkdownString;

305 306
	readonly visible: boolean;

307 308 309 310
	readonly onDidExpandItem: Event<ITreeItem>;

	readonly onDidCollapseItem: Event<ITreeItem>;

311 312
	readonly onDidChangeSelection: Event<ITreeItem[]>;

313 314
	readonly onDidChangeVisibility: Event<boolean>;

315
	readonly onDidChangeActions: Event<void>;
S
Sandeep Somavarapu 已提交
316

317
	refresh(treeItems?: ITreeItem[]): Promise<void>;
S
Sandeep Somavarapu 已提交
318

319
	setVisibility(visible: boolean): void;
S
Sandeep Somavarapu 已提交
320

321 322 323 324
	focus(): void;

	layout(height: number): void;

S
Sandeep Somavarapu 已提交
325
	show(container: HTMLElement);
326 327

	getOptimalWidth(): number;
S
Sandeep Somavarapu 已提交
328

J
Johannes Rieken 已提交
329
	reveal(item: ITreeItem): Promise<void>;
330

J
Johannes Rieken 已提交
331
	expand(itemOrItems: ITreeItem | ITreeItem[]): Promise<void>;
332 333 334 335

	setSelection(items: ITreeItem[]): void;

	setFocus(item: ITreeItem): void;
336 337 338 339

	getPrimaryActions(): IAction[];

	getSecondaryActions(): IAction[];
S
Sandeep Somavarapu 已提交
340 341
}

342 343 344 345 346 347 348 349 350 351
export interface IRevealOptions {

	select?: boolean;

	focus?: boolean;

	expand?: boolean | number;

}

352
export interface ITreeViewDescriptor extends IViewDescriptor {
S
Sandeep Somavarapu 已提交
353

S
rename  
Sandeep Somavarapu 已提交
354
	readonly treeView: ITreeView;
355

S
Sandeep Somavarapu 已提交
356
}
S
Sandeep Somavarapu 已提交
357 358 359

export type TreeViewItemHandleArg = {
	$treeViewId: string,
S
Sandeep Somavarapu 已提交
360
	$treeItemHandle: string
S
Sandeep Somavarapu 已提交
361 362 363 364 365 366 367 368
};

export enum TreeItemCollapsibleState {
	None = 0,
	Collapsed = 1,
	Expanded = 2
}

S
Sandeep Somavarapu 已提交
369 370 371 372
export interface ITreeItemLabel {

	label: string;

373
	highlights?: [number, number][];
S
Sandeep Somavarapu 已提交
374 375 376

}

S
Sandeep Somavarapu 已提交
377 378
export interface ITreeItem {

S
Sandeep Somavarapu 已提交
379
	handle: string;
S
Sandeep Somavarapu 已提交
380

S
Sandeep Somavarapu 已提交
381 382
	parentHandle: string;

S
Sandeep Somavarapu 已提交
383 384
	collapsibleState: TreeItemCollapsibleState;

S
Sandeep Somavarapu 已提交
385
	label?: ITreeItemLabel;
S
Sandeep Somavarapu 已提交
386

387 388
	description?: string | boolean;

389
	icon?: UriComponents;
S
Sandeep Somavarapu 已提交
390

391
	iconDark?: UriComponents;
S
Sandeep Somavarapu 已提交
392

S
Sandeep Somavarapu 已提交
393
	themeIcon?: ThemeIcon;
S
Sandeep Somavarapu 已提交
394

S
Sandeep Somavarapu 已提交
395 396
	resourceUri?: UriComponents;

S
Sandeep Somavarapu 已提交
397 398
	tooltip?: string;

S
Sandeep Somavarapu 已提交
399 400 401 402 403 404 405 406 407
	contextValue?: string;

	command?: Command;

	children?: ITreeItem[];
}

export interface ITreeViewDataProvider {

408
	getChildren(element?: ITreeItem): Promise<ITreeItem[]>;
S
Sandeep Somavarapu 已提交
409

I
isidor 已提交
410
}