views.ts 12.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
import { ContextKeyExpr, RawContextKey } from 'vs/platform/contextkey/common/contextkey';
S
Sandeep Somavarapu 已提交
10 11
import { localize } from 'vs/nls';
import { IViewlet } from 'vs/workbench/common/viewlet';
12
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
13
import { IDisposable, Disposable } from 'vs/base/common/lifecycle';
S
Sandeep Somavarapu 已提交
14
import { ThemeIcon } from 'vs/platform/theme/common/themeService';
S
Sandeep Somavarapu 已提交
15
import { values, keys } from 'vs/base/common/map';
S
Sandeep Somavarapu 已提交
16
import { Registry } from 'vs/platform/registry/common/platform';
S
Sandeep Somavarapu 已提交
17
import { IKeybindings } from 'vs/platform/keybinding/common/keybindingsRegistry';
18
import { IAction } from 'vs/base/common/actions';
19
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
S
Sandeep Somavarapu 已提交
20

21
export const TEST_VIEW_CONTAINER_ID = 'workbench.view.extension.test';
S
Sandeep Somavarapu 已提交
22
export const FocusedViewContext = new RawContextKey<string>('focusedView', '');
S
Sandeep Somavarapu 已提交
23

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

29 30 31 32 33
export enum ViewContainerLocation {
	Sidebar,
	Panel
}

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

S
Sandeep Somavarapu 已提交
40 41 42 43 44
	/**
	 * An event that is triggerred when a view container is deregistered.
	 */
	readonly onDidDeregister: Event<ViewContainer>;

S
Sandeep Somavarapu 已提交
45 46 47 48 49 50 51 52 53 54 55 56 57
	/**
	 * 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.
	 */
58
	registerViewContainer(id: string, location: ViewContainerLocation, hideIfEmpty?: boolean, extensionId?: ExtensionIdentifier, viewOrderDelegate?: ViewOrderDelegate): ViewContainer;
S
Sandeep Somavarapu 已提交
59

S
Sandeep Somavarapu 已提交
60 61 62 63 64 65
	/**
	 * Deregisters the given view container
	 * No op if the view container is not registered
	 */
	deregisterViewContainer(viewContainer: ViewContainer): void;

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

74 75 76 77
interface ViewOrderDelegate {
	getOrder(group?: string): number | undefined;
}

S
Sandeep Somavarapu 已提交
78
export class ViewContainer {
79
	protected constructor(readonly id: string, readonly location: ViewContainerLocation, readonly hideIfEmpty: boolean, readonly extensionId?: ExtensionIdentifier, readonly orderDelegate?: ViewOrderDelegate) { }
S
Sandeep Somavarapu 已提交
80 81
}

82
class ViewContainersRegistryImpl extends Disposable implements IViewContainersRegistry {
S
Sandeep Somavarapu 已提交
83

84
	private readonly _onDidRegister = this._register(new Emitter<ViewContainer>());
S
Sandeep Somavarapu 已提交
85
	readonly onDidRegister: Event<ViewContainer> = this._onDidRegister.event;
86

87
	private readonly _onDidDeregister = this._register(new Emitter<ViewContainer>());
S
Sandeep Somavarapu 已提交
88 89
	readonly onDidDeregister: Event<ViewContainer> = this._onDidDeregister.event;

S
Sandeep Somavarapu 已提交
90 91 92 93 94 95
	private viewContainers: Map<string, ViewContainer> = new Map<string, ViewContainer>();

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

96
	registerViewContainer(id: string, location: ViewContainerLocation, hideIfEmpty?: boolean, extensionId?: ExtensionIdentifier, viewOrderDelegate?: ViewOrderDelegate): ViewContainer {
97 98 99
		const existing = this.viewContainers.get(id);
		if (existing) {
			return existing;
S
Sandeep Somavarapu 已提交
100
		}
101 102 103

		const viewContainer = new class extends ViewContainer {
			constructor() {
104
				super(id, location, !!hideIfEmpty, extensionId, viewOrderDelegate);
105 106 107 108 109
			}
		};
		this.viewContainers.set(id, viewContainer);
		this._onDidRegister.fire(viewContainer);
		return viewContainer;
S
Sandeep Somavarapu 已提交
110 111
	}

S
Sandeep Somavarapu 已提交
112 113 114 115 116 117 118 119
	deregisterViewContainer(viewContainer: ViewContainer): void {
		const existing = this.viewContainers.get(viewContainer.id);
		if (existing) {
			this.viewContainers.delete(viewContainer.id);
			this._onDidDeregister.fire(viewContainer);
		}
	}

120
	get(id: string): ViewContainer | undefined {
S
Sandeep Somavarapu 已提交
121 122
		return this.viewContainers.get(id);
	}
S
Sandeep Somavarapu 已提交
123 124
}

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

S
Sandeep Somavarapu 已提交
127 128 129 130 131 132
export interface IViewDescriptor {

	readonly id: string;

	readonly name: string;

133
	readonly ctorDescriptor: { ctor: any, arguments?: any[] };
S
Sandeep Somavarapu 已提交
134 135 136 137 138 139 140 141 142 143

	readonly when?: ContextKeyExpr;

	readonly order?: number;

	readonly weight?: number;

	readonly collapsed?: boolean;

	readonly canToggleVisibility?: boolean;
144

145
	// Applies only to newly created views
146
	readonly hideByDefault?: boolean;
S
Sandeep Somavarapu 已提交
147

S
Sandeep Somavarapu 已提交
148 149
	readonly workspace?: boolean;

S
Sandeep Somavarapu 已提交
150
	readonly focusCommand?: { id: string, keybindings?: IKeybindings };
151 152 153 154

	// For contributed remote explorer views
	readonly group?: string;

155
	readonly remoteAuthority?: string | string[];
S
Sandeep Somavarapu 已提交
156 157
}

S
Sandeep Somavarapu 已提交
158
export interface IViewDescriptorCollection extends IDisposable {
S
Sandeep Somavarapu 已提交
159 160
	readonly onDidChangeActiveViews: Event<{ added: IViewDescriptor[], removed: IViewDescriptor[] }>;
	readonly activeViewDescriptors: IViewDescriptor[];
S
Sandeep Somavarapu 已提交
161
	readonly allViewDescriptors: IViewDescriptor[];
162 163
}

S
Sandeep Somavarapu 已提交
164 165
export interface IViewsRegistry {

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

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

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

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

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

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

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

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

182
	getViewContainer(id: string): ViewContainer | null;
S
Sandeep Somavarapu 已提交
183 184
}

185
class ViewsRegistry extends Disposable implements IViewsRegistry {
S
Sandeep Somavarapu 已提交
186

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

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

193
	private readonly _onDidChangeContainer: Emitter<{ views: IViewDescriptor[], from: ViewContainer, to: ViewContainer }> = this._register(new Emitter<{ views: IViewDescriptor[], from: ViewContainer, to: ViewContainer }>());
194 195
	readonly onDidChangeContainer: Event<{ views: IViewDescriptor[], from: ViewContainer, to: ViewContainer }> = this._onDidChangeContainer.event;

196
	private _viewContainers: ViewContainer[] = [];
S
Sandeep Somavarapu 已提交
197
	private _views: Map<ViewContainer, IViewDescriptor[]> = new Map<ViewContainer, IViewDescriptor[]>();
S
Sandeep Somavarapu 已提交
198

S
Sandeep Somavarapu 已提交
199 200 201
	registerViews(views: IViewDescriptor[], viewContainer: ViewContainer): void {
		this.addViews(views, viewContainer);
		this._onViewsRegistered.fire({ views: views, viewContainer });
S
Sandeep Somavarapu 已提交
202 203
	}

S
Sandeep Somavarapu 已提交
204 205 206 207
	deregisterViews(viewDescriptors: IViewDescriptor[], viewContainer: ViewContainer): void {
		const views = this.removeViews(viewDescriptors, viewContainer);
		if (views.length) {
			this._onViewsDeregistered.fire({ views, viewContainer });
S
Sandeep Somavarapu 已提交
208 209 210
		}
	}

S
Sandeep Somavarapu 已提交
211 212
	moveViews(viewsToMove: IViewDescriptor[], viewContainer: ViewContainer): void {
		keys(this._views).forEach(container => {
213
			if (container !== viewContainer) {
S
Sandeep Somavarapu 已提交
214 215 216 217
				const views = this.removeViews(viewsToMove, container);
				if (views.length) {
					this.addViews(views, viewContainer);
					this._onDidChangeContainer.fire({ views, from: container, to: viewContainer });
218 219 220 221 222
				}
			}
		});
	}

S
Sandeep Somavarapu 已提交
223
	getViews(loc: ViewContainer): IViewDescriptor[] {
S
Sandeep Somavarapu 已提交
224 225 226
		return this._views.get(loc) || [];
	}

M
Matt Bierner 已提交
227
	getView(id: string): IViewDescriptor | null {
228
		for (const viewContainer of this._viewContainers) {
S
Sandeep Somavarapu 已提交
229
			const viewDescriptor = (this._views.get(viewContainer) || []).filter(v => v.id === id)[0];
S
Sandeep Somavarapu 已提交
230 231 232 233 234
			if (viewDescriptor) {
				return viewDescriptor;
			}
		}
		return null;
S
Sandeep Somavarapu 已提交
235
	}
S
Sandeep Somavarapu 已提交
236

237 238 239 240 241 242 243 244
	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 已提交
245
	}
S
Sandeep Somavarapu 已提交
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 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285

	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;
	}
286 287 288
}

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

S
Sandeep Somavarapu 已提交
290 291 292 293 294 295
export interface IView {

	readonly id: string;

}

S
Sandeep Somavarapu 已提交
296 297
export interface IViewsViewlet extends IViewlet {

I
isidor 已提交
298
	openView(id: string, focus?: boolean): IView;
S
Sandeep Somavarapu 已提交
299 300 301

}

302 303 304
export const IViewsService = createDecorator<IViewsService>('viewsService');

export interface IViewsService {
305
	_serviceBrand: undefined;
306

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

S
Sandeep Somavarapu 已提交
309
	getViewDescriptors(container: ViewContainer): IViewDescriptorCollection | null;
310 311
}

S
Sandeep Somavarapu 已提交
312 313
// Custom views

S
rename  
Sandeep Somavarapu 已提交
314
export interface ITreeView extends IDisposable {
315

316
	dataProvider: ITreeViewDataProvider | undefined;
S
Sandeep Somavarapu 已提交
317

318 319
	showCollapseAllAction: boolean;

320 321
	canSelectMany: boolean;

322
	message?: string;
323

324 325
	title: string;

326 327
	readonly visible: boolean;

328 329 330 331
	readonly onDidExpandItem: Event<ITreeItem>;

	readonly onDidCollapseItem: Event<ITreeItem>;

332 333
	readonly onDidChangeSelection: Event<ITreeItem[]>;

334 335
	readonly onDidChangeVisibility: Event<boolean>;

336
	readonly onDidChangeActions: Event<void>;
S
Sandeep Somavarapu 已提交
337

338 339
	readonly onDidChangeTitle: Event<string>;

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

342
	setVisibility(visible: boolean): void;
S
Sandeep Somavarapu 已提交
343

344 345
	focus(): void;

346
	layout(height: number, width: number): void;
347 348

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

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

J
Johannes Rieken 已提交
352
	expand(itemOrItems: ITreeItem | ITreeItem[]): Promise<void>;
353 354 355 356

	setSelection(items: ITreeItem[]): void;

	setFocus(item: ITreeItem): void;
357 358 359 360

	getPrimaryActions(): IAction[];

	getSecondaryActions(): IAction[];
S
Sandeep Somavarapu 已提交
361 362
}

363 364 365 366 367 368 369 370 371 372
export interface IRevealOptions {

	select?: boolean;

	focus?: boolean;

	expand?: boolean | number;

}

373
export interface ITreeViewDescriptor extends IViewDescriptor {
S
Sandeep Somavarapu 已提交
374

S
rename  
Sandeep Somavarapu 已提交
375
	readonly treeView: ITreeView;
376

S
Sandeep Somavarapu 已提交
377
}
S
Sandeep Somavarapu 已提交
378 379 380

export type TreeViewItemHandleArg = {
	$treeViewId: string,
S
Sandeep Somavarapu 已提交
381
	$treeItemHandle: string
S
Sandeep Somavarapu 已提交
382 383 384 385 386 387 388 389
};

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

S
Sandeep Somavarapu 已提交
390 391 392 393
export interface ITreeItemLabel {

	label: string;

394
	highlights?: [number, number][];
S
Sandeep Somavarapu 已提交
395 396 397

}

S
Sandeep Somavarapu 已提交
398 399
export interface ITreeItem {

S
Sandeep Somavarapu 已提交
400
	handle: string;
S
Sandeep Somavarapu 已提交
401

S
Sandeep Somavarapu 已提交
402
	parentHandle?: string;
S
Sandeep Somavarapu 已提交
403

S
Sandeep Somavarapu 已提交
404 405
	collapsibleState: TreeItemCollapsibleState;

S
Sandeep Somavarapu 已提交
406
	label?: ITreeItemLabel;
S
Sandeep Somavarapu 已提交
407

408 409
	description?: string | boolean;

410
	icon?: UriComponents;
S
Sandeep Somavarapu 已提交
411

412
	iconDark?: UriComponents;
S
Sandeep Somavarapu 已提交
413

S
Sandeep Somavarapu 已提交
414
	themeIcon?: ThemeIcon;
S
Sandeep Somavarapu 已提交
415

S
Sandeep Somavarapu 已提交
416 417
	resourceUri?: UriComponents;

S
Sandeep Somavarapu 已提交
418 419
	tooltip?: string;

S
Sandeep Somavarapu 已提交
420 421 422 423 424 425 426 427 428
	contextValue?: string;

	command?: Command;

	children?: ITreeItem[];
}

export interface ITreeViewDataProvider {

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

I
isidor 已提交
431
}
432 433 434 435 436 437 438

export interface IEditableData {
	validationMessage: (value: string) => string | null;
	placeholder?: string | null;
	startingValue?: string | null;
	onFinish: (value: string, success: boolean) => void;
}