views.ts 11.7 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';
13
import { createDecorator, ServiceIdentifier } 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
export namespace Extensions {
	export const ViewContainersRegistry = 'workbench.registry.view.containers';
27
	export const ViewsRegistry = 'workbench.registry.view';
S
Sandeep Somavarapu 已提交
28
}
S
Sandeep Somavarapu 已提交
29

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

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

S
Sandeep Somavarapu 已提交
41 42 43 44 45 46 47 48 49 50 51 52 53
	/**
	 * 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.
	 */
54
	registerViewContainer(id: string, hideIfEmpty?: boolean, extensionId?: ExtensionIdentifier): ViewContainer;
S
Sandeep Somavarapu 已提交
55

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

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

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

class ViewContainersRegistryImpl implements IViewContainersRegistry {

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

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

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

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

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

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

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

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

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

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

	readonly id: string;

	readonly name: string;

125
	readonly ctorDescriptor: { ctor: any, arguments?: any[] };
S
Sandeep Somavarapu 已提交
126 127 128 129 130 131 132 133 134 135

	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
class ViewsRegistry implements IViewsRegistry {
S
Sandeep Somavarapu 已提交
171

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;
	}
271 272 273
}

Registry.add(Extensions.ViewsRegistry, new ViewsRegistry());
S
Sandeep Somavarapu 已提交
274

S
Sandeep Somavarapu 已提交
275 276 277 278 279 280
export interface IView {

	readonly id: string;

}

S
Sandeep Somavarapu 已提交
281 282
export interface IViewsViewlet extends IViewlet {

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

}

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

export interface IViewsService {
290
	_serviceBrand: ServiceIdentifier<any>;
291

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

S
Sandeep Somavarapu 已提交
294
	getViewDescriptors(container: ViewContainer): IViewDescriptorCollection | null;
295 296
}

S
Sandeep Somavarapu 已提交
297 298
// Custom views

S
rename  
Sandeep Somavarapu 已提交
299
export interface ITreeView extends IDisposable {
300

301
	dataProvider: ITreeViewDataProvider | null;
S
Sandeep Somavarapu 已提交
302

303 304
	showCollapseAllAction: boolean;

M
Matt Bierner 已提交
305
	message?: string | IMarkdownString;
306

307 308
	readonly visible: boolean;

309 310 311 312
	readonly onDidExpandItem: Event<ITreeItem>;

	readonly onDidCollapseItem: Event<ITreeItem>;

313 314
	readonly onDidChangeSelection: Event<ITreeItem[]>;

315 316
	readonly onDidChangeVisibility: Event<boolean>;

317
	readonly onDidChangeActions: Event<void>;
S
Sandeep Somavarapu 已提交
318

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

321
	setVisibility(visible: boolean): void;
S
Sandeep Somavarapu 已提交
322

323 324 325 326
	focus(): void;

	layout(height: number): void;

327
	show(container: HTMLElement): void;
328 329

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

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

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

	setSelection(items: ITreeItem[]): void;

	setFocus(item: ITreeItem): void;
338 339 340 341

	getPrimaryActions(): IAction[];

	getSecondaryActions(): IAction[];
S
Sandeep Somavarapu 已提交
342 343
}

344 345 346 347 348 349 350 351 352 353
export interface IRevealOptions {

	select?: boolean;

	focus?: boolean;

	expand?: boolean | number;

}

354
export interface ITreeViewDescriptor extends IViewDescriptor {
S
Sandeep Somavarapu 已提交
355

S
rename  
Sandeep Somavarapu 已提交
356
	readonly treeView: ITreeView;
357

S
Sandeep Somavarapu 已提交
358
}
S
Sandeep Somavarapu 已提交
359 360 361

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

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

S
Sandeep Somavarapu 已提交
371 372 373 374
export interface ITreeItemLabel {

	label: string;

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

}

S
Sandeep Somavarapu 已提交
379 380
export interface ITreeItem {

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

M
Matt Bierner 已提交
383
	parentHandle: string | null;
S
Sandeep Somavarapu 已提交
384

S
Sandeep Somavarapu 已提交
385 386
	collapsibleState: TreeItemCollapsibleState;

S
Sandeep Somavarapu 已提交
387
	label?: ITreeItemLabel;
S
Sandeep Somavarapu 已提交
388

389 390
	description?: string | boolean;

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

393
	iconDark?: UriComponents;
S
Sandeep Somavarapu 已提交
394

S
Sandeep Somavarapu 已提交
395
	themeIcon?: ThemeIcon;
S
Sandeep Somavarapu 已提交
396

S
Sandeep Somavarapu 已提交
397 398
	resourceUri?: UriComponents;

S
Sandeep Somavarapu 已提交
399 400
	tooltip?: string;

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

	command?: Command;

	children?: ITreeItem[];
}

export interface ITreeViewDataProvider {

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

I
isidor 已提交
412
}