views.ts 11.6 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 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, hideIfEmpty?: boolean, 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 hideIfEmpty: boolean, 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, hideIfEmpty?: boolean, extensionId?: ExtensionIdentifier): ViewContainer {
88 89 90
		const existing = this.viewContainers.get(id);
		if (existing) {
			return existing;
S
Sandeep Somavarapu 已提交
91
		}
92 93 94

		const viewContainer = new class extends ViewContainer {
			constructor() {
S
Sandeep Somavarapu 已提交
95
				super(id, !!hideIfEmpty, extensionId);
96 97 98 99 100
			}
		};
		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;

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

	readonly when?: ContextKeyExpr;

	readonly order?: number;

	readonly weight?: number;

	readonly collapsed?: boolean;

	readonly canToggleVisibility?: boolean;
135

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

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

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

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

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

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

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

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

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

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

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

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

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

export const ViewsRegistry: IViewsRegistry = new class implements IViewsRegistry {

171 172
	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 已提交
173

174 175
	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 已提交
176

177 178 179
	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;

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

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

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

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

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

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

221 222 223 224 225 226 227 228
	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 已提交
229
	}
S
Sandeep Somavarapu 已提交
230 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

	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 已提交
270 271
};

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

	readonly id: string;

}

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

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

}

284 285 286
export const IViewsService = createDecorator<IViewsService>('viewsService');

export interface IViewsService {
287
	_serviceBrand: ServiceIdentifier<any>;
288

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

S
Sandeep Somavarapu 已提交
291
	getViewDescriptors(container: ViewContainer): IViewDescriptorCollection | null;
292 293
}

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

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

298
	dataProvider: ITreeViewDataProvider | null;
S
Sandeep Somavarapu 已提交
299

300 301
	showCollapseAllAction: boolean;

M
Matt Bierner 已提交
302
	message?: string | IMarkdownString;
303

304 305
	readonly visible: boolean;

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

	readonly onDidCollapseItem: Event<ITreeItem>;

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

312 313
	readonly onDidChangeVisibility: Event<boolean>;

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

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

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

320 321 322 323
	focus(): void;

	layout(height: number): void;

324
	show(container: HTMLElement): void;
325 326

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

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

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

	setSelection(items: ITreeItem[]): void;

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

	getPrimaryActions(): IAction[];

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

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

	select?: boolean;

	focus?: boolean;

	expand?: boolean | number;

}

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

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

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

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

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

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

	label: string;

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

}

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

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

M
Matt Bierner 已提交
380
	parentHandle: string | null;
S
Sandeep Somavarapu 已提交
381

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

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

386 387
	description?: string | boolean;

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

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

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

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

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

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

	command?: Command;

	children?: ITreeItem[];
}

export interface ITreeViewDataProvider {

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

I
isidor 已提交
409
}