/*--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ 'use strict'; import { localize } from 'vs/nls'; import * as vscode from 'vscode'; import { TPromise } from 'vs/base/common/winjs.base'; import { SqlMainContext, ExtHostModelViewTreeViewsShape, MainThreadModelViewShape } from 'sql/workbench/api/node/sqlExtHost.protocol'; import { ITreeComponentItem } from 'sql/workbench/common/views'; import { CommandsConverter } from 'vs/workbench/api/node/extHostCommands'; import { asWinJsPromise } from 'vs/base/common/async'; import { IMainContext } from 'vs/workbench/api/node/extHost.protocol'; import * as sqlops from 'sqlops'; import * as vsTreeExt from 'vs/workbench/api/node/extHostTreeViews'; import { Emitter } from 'vs/base/common/event'; export class ExtHostModelViewTreeViews implements ExtHostModelViewTreeViewsShape { private _proxy: MainThreadModelViewShape; private treeViews: Map> = new Map>(); constructor( private _mainContext: IMainContext ) { this._proxy = this._mainContext.getProxy(SqlMainContext.MainThreadModelView); } $createTreeView(handle: number, componentId: string, options: { treeDataProvider: sqlops.TreeComponentDataProvider }): sqlops.TreeComponentView { if (!options || !options.treeDataProvider) { throw new Error('Options with treeDataProvider is mandatory'); } const treeView = this.createExtHostTreeViewer(handle, componentId, options.treeDataProvider); return { dispose: () => { this.treeViews.delete(componentId); treeView.dispose(); }, onNodeCheckedChanged: treeView.NodeCheckedChanged, onDidChangeSelection: treeView.ChangeSelection }; } $getChildren(treeViewId: string, treeItemHandle?: string): TPromise { const treeView = this.treeViews.get(treeViewId); if (!treeView) { return TPromise.wrapError(new Error(localize('treeView.notRegistered', 'No tree view with id \'{0}\' registered.', treeViewId))); } return treeView.getChildren(treeItemHandle); } $onNodeCheckedChanged(treeViewId: string, treeItemHandle?: string, checked?: boolean): void { const treeView = this.treeViews.get(treeViewId); if (treeView) { treeView.onNodeCheckedChanged(treeItemHandle, checked); } } $onNodeSelected(treeViewId: string, handles: string[]): void { const treeView = this.treeViews.get(treeViewId); if (treeView) { treeView.onNodeSelectedChanged(handles); } } $setExpanded(treeViewId: string, treeItemHandle: string, expanded: boolean): void { } $setSelection(treeViewId: string, treeItemHandles: string[]): void { } $setVisible(treeViewId: string, visible: boolean): void { } private createExtHostTreeViewer(handle: number, id: string, dataProvider: sqlops.TreeComponentDataProvider): ExtHostTreeView { const treeView = new ExtHostTreeView(handle, id, dataProvider, this._proxy, undefined); this.treeViews.set(`${handle}-${id}`, treeView); return treeView; } } export class ExtHostTreeView extends vsTreeExt.ExtHostTreeView { private _onNodeCheckedChanged = new Emitter>(); private _onChangeSelection = new Emitter>(); public readonly NodeCheckedChanged: vscode.Event> = this._onNodeCheckedChanged.event; public readonly ChangeSelection: vscode.Event> = this._onChangeSelection.event; constructor( private handle: number, private componentId: string, private componentDataProvider: sqlops.TreeComponentDataProvider, private modelViewProxy: MainThreadModelViewShape, commands: CommandsConverter) { super(componentId, componentDataProvider, undefined, commands, undefined); } onNodeCheckedChanged(parentHandle?: vsTreeExt.TreeItemHandle, checked?: boolean): void { const parentElement = parentHandle ? this.getExtensionElement(parentHandle) : void 0; if (parentHandle && !parentElement) { console.error(`No tree item with id \'${parentHandle}\' found.`); } this._onNodeCheckedChanged.fire({element: parentElement, checked: checked}); } onNodeSelectedChanged(parentHandles?: vsTreeExt.TreeItemHandle[]): void { if (parentHandles) { let nodes = parentHandles.map(parentHandle => { return parentHandle ? this.getExtensionElement(parentHandle) : void 0; }); this._onChangeSelection.fire({ selection: nodes}); } } reveal(element: T, options?: { select?: boolean }): TPromise { if (typeof this.componentDataProvider.getParent !== 'function') { return TPromise.wrapError(new Error(`Required registered TreeDataProvider to implement 'getParent' method to access 'reveal' method`)); } let i: void; return this.resolveUnknownParentChain(element) .then(parentChain => this.resolveTreeNode(element, parentChain[parentChain.length - 1]) .then(treeNode => i)); } protected refreshElements(elements: T[]): void { const hasRoot = elements.some(element => !element); if (hasRoot) { this.clearAll(); // clear cache this.modelViewProxy.$refreshDataProvider(this.handle, this.componentId); } else { const handlesToRefresh = this.getHandlesToRefresh(elements); if (handlesToRefresh.length) { this.refreshHandles(handlesToRefresh); } } } protected refreshHandles(itemHandles: vsTreeExt.TreeItemHandle[]): TPromise { const itemsToRefresh: { [treeItemHandle: string]: ITreeComponentItem } = {}; return TPromise.join(itemHandles.map(treeItemHandle => this.refreshNode(treeItemHandle) .then(node => { if (node) { itemsToRefresh[treeItemHandle] = node.item; } }))) .then(() => Object.keys(itemsToRefresh).length ? this.modelViewProxy.$refreshDataProvider(this.handle, this.componentId, itemsToRefresh) : null); } protected refreshNode(treeItemHandle: vsTreeExt.TreeItemHandle): TPromise { const extElement = this.getExtensionElement(treeItemHandle); const existing = this.nodes.get(extElement); //this.clearChildren(extElement); // clear children cache return asWinJsPromise(() => this.componentDataProvider.getTreeItem(extElement)) .then(extTreeItem => { if (extTreeItem) { const newNode = this.createTreeNode(extElement, extTreeItem, existing.parent); this.updateNodeCache(extElement, newNode, existing, existing.parent); return newNode; } return null; }); } protected createTreeItem(element: T, extensionTreeItem: sqlops.TreeComponentItem, parent?: vsTreeExt.TreeNode): ITreeComponentItem { let item = super.createTreeItem(element, extensionTreeItem, parent); item = Object.assign({}, item, { checked: extensionTreeItem.checked }); return item; } }