/*--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ import { TPromise } from 'vs/base/common/winjs.base'; import { Command } from 'vs/editor/common/modes'; import { UriComponents } from 'vs/base/common/uri'; import { Event, Emitter } from 'vs/base/common/event'; 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'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { IDisposable } from 'vs/base/common/lifecycle'; import { ThemeIcon } from 'vs/platform/theme/common/themeService'; export class ViewLocation { static readonly Explorer = new ViewLocation('workbench.view.explorer'); static readonly Debug = new ViewLocation('workbench.view.debug'); static readonly Extensions = new ViewLocation('workbench.view.extensions'); constructor(private _id: string) { } get id(): string { return this._id; } static getContributedViewLocation(value: string): ViewLocation { switch (value) { case 'explorer': return ViewLocation.Explorer; case 'debug': return ViewLocation.Debug; } return void 0; } } export interface IViewDescriptor { readonly id: string; readonly name: string; readonly location: ViewLocation; // TODO do we really need this?! readonly ctor: any; readonly when?: ContextKeyExpr; readonly order?: number; readonly weight?: number; readonly collapsed?: boolean; readonly canToggleVisibility?: boolean; } export interface IViewsRegistry { readonly onViewsRegistered: Event; readonly onViewsDeregistered: Event; registerViews(views: IViewDescriptor[]): void; deregisterViews(ids: string[], location: ViewLocation): void; getViews(loc: ViewLocation): IViewDescriptor[]; getAllViews(): IViewDescriptor[]; getView(id: string): IViewDescriptor; } export const ViewsRegistry: IViewsRegistry = new class implements IViewsRegistry { private readonly _onViewsRegistered: Emitter = new Emitter(); readonly onViewsRegistered: Event = this._onViewsRegistered.event; private readonly _onViewsDeregistered: Emitter = new Emitter(); readonly onViewsDeregistered: Event = this._onViewsDeregistered.event; private _viewLocations: ViewLocation[] = []; private _views: Map = new Map(); registerViews(viewDescriptors: IViewDescriptor[]): void { if (viewDescriptors.length) { for (const viewDescriptor of viewDescriptors) { let views = this._views.get(viewDescriptor.location); if (!views) { views = []; this._views.set(viewDescriptor.location, views); this._viewLocations.push(viewDescriptor.location); } if (views.some(v => v.id === viewDescriptor.id)) { throw new Error(localize('duplicateId', "A view with id '{0}' is already registered in the location '{1}'", viewDescriptor.id, viewDescriptor.location.id)); } views.push(viewDescriptor); } this._onViewsRegistered.fire(viewDescriptors); } } deregisterViews(ids: string[], location: ViewLocation): void { const views = this._views.get(location); if (!views) { return; } const viewsToDeregister = views.filter(view => ids.indexOf(view.id) !== -1); if (viewsToDeregister.length) { const remaningViews = views.filter(view => ids.indexOf(view.id) === -1); if (remaningViews.length) { this._views.set(location, remaningViews); } else { this._views.delete(location); this._viewLocations.splice(this._viewLocations.indexOf(location), 1); } } this._onViewsDeregistered.fire(viewsToDeregister); } getViews(loc: ViewLocation): IViewDescriptor[] { return this._views.get(loc) || []; } getAllViews(): IViewDescriptor[] { const result: IViewDescriptor[] = []; this._views.forEach(views => result.push(...views)); return result; } getView(id: string): IViewDescriptor { for (const viewLocation of this._viewLocations) { const viewDescriptor = (this._views.get(viewLocation) || []).filter(v => v.id === id)[0]; if (viewDescriptor) { return viewDescriptor; } } return null; } }; export interface IViewsViewlet extends IViewlet { openView(id: string, focus?: boolean): TPromise; } // Custom views export interface ITreeViewer extends IDisposable { dataProvider: ITreeViewDataProvider; refresh(treeItems?: ITreeItem[]): TPromise; setVisibility(visible: boolean): void; focus(): void; layout(height: number): void; show(container: HTMLElement); getOptimalWidth(): number; reveal(item: ITreeItem, parentChain: ITreeItem[], options: { select?: boolean }): TPromise; } export interface ICustomViewDescriptor extends IViewDescriptor { treeView?: boolean; } export const ICustomViewsService = createDecorator('customViewsService'); export interface ICustomViewsService { _serviceBrand: any; getTreeViewer(id: string): ITreeViewer; openView(id: string, focus?: boolean): TPromise; } export type TreeViewItemHandleArg = { $treeViewId: string, $treeItemHandle: string }; export enum TreeItemCollapsibleState { None = 0, Collapsed = 1, Expanded = 2 } export interface ITreeItem { handle: string; parentHandle: string; collapsibleState: TreeItemCollapsibleState; label?: string; icon?: string; iconDark?: string; themeIcon?: ThemeIcon; resourceUri?: UriComponents; tooltip?: string; contextValue?: string; command?: Command; children?: ITreeItem[]; } export interface ITreeViewDataProvider { onDidChange: Event; onDispose: Event; getChildren(element?: ITreeItem): TPromise; }