From 76d99c7ed918cc5c6987bd1b35ee8d0c8845ab30 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Mon, 18 Jun 2018 19:07:07 +0200 Subject: [PATCH 1/6] selection change event --- src/vs/vscode.d.ts | 17 +++++++++++++++++ src/vs/workbench/api/node/extHostTreeViews.ts | 14 +++++++++++--- 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/src/vs/vscode.d.ts b/src/vs/vscode.d.ts index fd657b4bdd7b8..4362959ed4d81 100644 --- a/src/vs/vscode.d.ts +++ b/src/vs/vscode.d.ts @@ -6079,6 +6079,18 @@ declare module 'vscode' { } + /** + * The event that is fired when there is a change in [tree view's selections](#TreeView.selections) + */ + export interface TreeViewSelectionChangeEvent { + + /** + * Selected elements. + */ + selections: T[]; + + } + /** * Represents a Tree view */ @@ -6094,6 +6106,11 @@ declare module 'vscode' { */ readonly onDidCollapseElement: Event>; + /** + * Event that is fired when the selection has changed + */ + readonly onDidChangeSelection: Event>; + /** * Currently selected elements. */ diff --git a/src/vs/workbench/api/node/extHostTreeViews.ts b/src/vs/workbench/api/node/extHostTreeViews.ts index 499e859b46f54..4287ad62e937c 100644 --- a/src/vs/workbench/api/node/extHostTreeViews.ts +++ b/src/vs/workbench/api/node/extHostTreeViews.ts @@ -17,6 +17,7 @@ import { ExtHostCommands, CommandsConverter } from 'vs/workbench/api/node/extHos import { asWinJsPromise } from 'vs/base/common/async'; import { TreeItemCollapsibleState, ThemeIcon } from 'vs/workbench/api/node/extHostTypes'; import { isUndefinedOrNull } from 'vs/base/common/types'; +import { equals } from 'vs/base/common/arrays'; type TreeItemHandle = string; @@ -51,6 +52,7 @@ export class ExtHostTreeViews implements ExtHostTreeViewsShape { return { get onDidCollapseElement() { return treeView.onDidCollapseElement; }, get onDidExpandElement() { return treeView.onDidExpandElement; }, + get onDidChangeSelection() { return treeView.onDidChangeSelection; }, get selection() { return treeView.selectedElements; }, reveal: (element: T, options?: { select?: boolean }): Thenable => { return treeView.reveal(element, options); @@ -113,8 +115,8 @@ class ExtHostTreeView extends Disposable { private elements: Map = new Map(); private nodes: Map = new Map(); - private _selectedElements: T[] = []; - get selectedElements(): T[] { return this._selectedElements; } + private _selectedHandles: TreeItemHandle[] = []; + get selectedElements(): T[] { return this._selectedHandles.map(handle => this.getExtensionElement(handle)).filter(element => !isUndefinedOrNull(element)); } private _onDidExpandElement: Emitter> = this._register(new Emitter>()); readonly onDidExpandElement: Event> = this._onDidExpandElement.event; @@ -122,6 +124,9 @@ class ExtHostTreeView extends Disposable { private _onDidCollapseElement: Emitter> = this._register(new Emitter>()); readonly onDidCollapseElement: Event> = this._onDidCollapseElement.event; + private _onDidChangeSelection: Emitter> = this._register(new Emitter>()); + readonly onDidChangeSelection: Event> = this._onDidChangeSelection.event; + private refreshPromise: TPromise = TPromise.as(null); constructor(private viewId: string, private dataProvider: vscode.TreeDataProvider, private proxy: MainThreadTreeViewsShape, private commands: CommandsConverter) { @@ -182,7 +187,10 @@ class ExtHostTreeView extends Disposable { } setSelection(treeItemHandles: TreeItemHandle[]): void { - this._selectedElements = treeItemHandles.map(handle => this.getExtensionElement(handle)).filter(element => !isUndefinedOrNull(element)); + if (!equals(this._selectedHandles, treeItemHandles)) { + this._selectedHandles = treeItemHandles; + this._onDidChangeSelection.fire({ selections: this.selectedElements }); + } } private resolveUnknownParentChain(element: T): TPromise { From bac400fe40c2d0e55108836d7bbb6bb08fba89a4 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Tue, 19 Jun 2018 11:34:01 +0200 Subject: [PATCH 2/6] Add support for visibility and focus --- src/vs/vscode.d.ts | 37 +++++++++++++++---- .../electron-browser/mainThreadTreeViews.ts | 5 ++- src/vs/workbench/api/node/extHost.protocol.ts | 3 +- src/vs/workbench/api/node/extHostTreeViews.ts | 37 ++++++++++++++++--- .../browser/parts/views/customView.ts | 17 +++++++-- .../browser/parts/views/viewsViewlet.ts | 4 +- src/vs/workbench/common/views.ts | 2 + 7 files changed, 85 insertions(+), 20 deletions(-) diff --git a/src/vs/vscode.d.ts b/src/vs/vscode.d.ts index 4362959ed4d81..cc0f3fc912602 100644 --- a/src/vs/vscode.d.ts +++ b/src/vs/vscode.d.ts @@ -6080,14 +6080,23 @@ declare module 'vscode' { } /** - * The event that is fired when there is a change in [tree view's selections](#TreeView.selections) + * The event that is fired when there is a change in [tree view's selection](#TreeView.selection) */ export interface TreeViewSelectionChangeEvent { /** * Selected elements. */ - selections: T[]; + selection: T[]; + + } + + export interface TreeViewVisibilityChangeEvent { + + /** + * `true` if the [tree view](#TreeView) is visible otherwise `false`. + */ + visible: boolean; } @@ -6107,26 +6116,38 @@ declare module 'vscode' { readonly onDidCollapseElement: Event>; /** - * Event that is fired when the selection has changed + * Currently selected elements. + */ + readonly selection: ReadonlyArray; + + /** + * Event that is fired when the [selection](#TreeView.selection) has changed */ readonly onDidChangeSelection: Event>; /** - * Currently selected elements. + * `true` if the [tree view](#TreeView) is visible otherwise `false`. */ - readonly selection: ReadonlyArray; + readonly visible: boolean; /** - * Reveal an element. By default revealed element is selected. + * Event that is fired when [visibility](TreeView.visible) has changed + */ + readonly onDidChangeVisibility: Event; + + /** + * Reveals the given element in the tree view. + * If the tree view is not visible then the element is revealed after the tree view is shown. * + * By default revealed element is selected and not focused. * In order to not to select, set the option `select` to `false`. + * In order to focus, set the option `focus` to `true`. * * **NOTE:** [TreeDataProvider](#TreeDataProvider) is required to implement [getParent](#TreeDataProvider.getParent) method to access this API. */ - reveal(element: T, options?: { select?: boolean }): Thenable; + reveal(element: T, options?: { select?: boolean, focus?: boolean }): Thenable; } - /** * A data provider that provides tree data */ diff --git a/src/vs/workbench/api/electron-browser/mainThreadTreeViews.ts b/src/vs/workbench/api/electron-browser/mainThreadTreeViews.ts index bf456a9571e59..f10dd9cc5a0c9 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadTreeViews.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadTreeViews.ts @@ -39,8 +39,8 @@ export class MainThreadTreeViews extends Disposable implements MainThreadTreeVie } } - $reveal(treeViewId: string, item: ITreeItem, parentChain: ITreeItem[], options?: { select?: boolean }): TPromise { - return this.viewsService.openView(treeViewId) + $reveal(treeViewId: string, item: ITreeItem, parentChain: ITreeItem[], options: { select: boolean, focus: boolean }): TPromise { + return this.viewsService.openView(treeViewId, options.focus) .then(() => { const viewer = this.getTreeViewer(treeViewId); return viewer ? viewer.reveal(item, parentChain, options) : null; @@ -61,6 +61,7 @@ export class MainThreadTreeViews extends Disposable implements MainThreadTreeVie this._register(treeViewer.onDidExpandItem(item => this._proxy.$setExpanded(treeViewId, item.handle, true))); this._register(treeViewer.onDidCollapseItem(item => this._proxy.$setExpanded(treeViewId, item.handle, false))); this._register(treeViewer.onDidChangeSelection(items => this._proxy.$setSelection(treeViewId, items.map(({ handle }) => handle)))); + this._register(treeViewer.onDidChangeVisibility(isVisible => this._proxy.$setVisible(treeViewId, isVisible))); } private getTreeViewer(treeViewId: string): ITreeViewer { diff --git a/src/vs/workbench/api/node/extHost.protocol.ts b/src/vs/workbench/api/node/extHost.protocol.ts index adbb6dd1a0b97..6f54537614882 100644 --- a/src/vs/workbench/api/node/extHost.protocol.ts +++ b/src/vs/workbench/api/node/extHost.protocol.ts @@ -215,7 +215,7 @@ export interface MainThreadTextEditorsShape extends IDisposable { export interface MainThreadTreeViewsShape extends IDisposable { $registerTreeViewDataProvider(treeViewId: string): void; $refresh(treeViewId: string, itemsToRefresh?: { [treeItemHandle: string]: ITreeItem }): TPromise; - $reveal(treeViewId: string, treeItem: ITreeItem, parentChain: ITreeItem[], options?: { select?: boolean }): TPromise; + $reveal(treeViewId: string, treeItem: ITreeItem, parentChain: ITreeItem[], options: { select: boolean, focus: boolean }): TPromise; } export interface MainThreadErrorsShape extends IDisposable { @@ -654,6 +654,7 @@ export interface ExtHostTreeViewsShape { $getChildren(treeViewId: string, treeItemHandle?: string): TPromise; $setExpanded(treeViewId: string, treeItemHandle: string, expanded: boolean): void; $setSelection(treeViewId: string, treeItemHandles: string[]): void; + $setVisible(treeViewId: string, visible: boolean): void; } export interface ExtHostWorkspaceShape { diff --git a/src/vs/workbench/api/node/extHostTreeViews.ts b/src/vs/workbench/api/node/extHostTreeViews.ts index 4287ad62e937c..2df9b9076cd79 100644 --- a/src/vs/workbench/api/node/extHostTreeViews.ts +++ b/src/vs/workbench/api/node/extHostTreeViews.ts @@ -52,9 +52,11 @@ export class ExtHostTreeViews implements ExtHostTreeViewsShape { return { get onDidCollapseElement() { return treeView.onDidCollapseElement; }, get onDidExpandElement() { return treeView.onDidExpandElement; }, - get onDidChangeSelection() { return treeView.onDidChangeSelection; }, get selection() { return treeView.selectedElements; }, - reveal: (element: T, options?: { select?: boolean }): Thenable => { + get onDidChangeSelection() { return treeView.onDidChangeSelection; }, + get visible() { return treeView.visible; }, + get onDidChangeVisibility() { return treeView.onDidChangeVisibility; }, + reveal: (element: T, options?: { select?: boolean, focus?: boolean }): Thenable => { return treeView.reveal(element, options); }, dispose: () => { @@ -88,6 +90,14 @@ export class ExtHostTreeViews implements ExtHostTreeViewsShape { treeView.setSelection(treeItemHandles); } + $setVisible(treeViewId: string, isVisible: boolean): void { + const treeView = this.treeViews.get(treeViewId); + if (!treeView) { + throw new Error(localize('treeView.notRegistered', 'No tree view with id \'{0}\' registered.', treeViewId)); + } + treeView.setVisible(isVisible); + } + private createExtHostTreeViewer(id: string, dataProvider: vscode.TreeDataProvider): ExtHostTreeView { const treeView = new ExtHostTreeView(id, dataProvider, this._proxy, this.commands.converter); this.treeViews.set(id, treeView); @@ -115,6 +125,9 @@ class ExtHostTreeView extends Disposable { private elements: Map = new Map(); private nodes: Map = new Map(); + private _visible: boolean = true; + get visible(): boolean { return this._visible; } + private _selectedHandles: TreeItemHandle[] = []; get selectedElements(): T[] { return this._selectedHandles.map(handle => this.getExtensionElement(handle)).filter(element => !isUndefinedOrNull(element)); } @@ -127,6 +140,9 @@ class ExtHostTreeView extends Disposable { private _onDidChangeSelection: Emitter> = this._register(new Emitter>()); readonly onDidChangeSelection: Event> = this._onDidChangeSelection.event; + private _onDidChangeVisibility: Emitter = this._register(new Emitter()); + readonly onDidChangeVisibility: Event = this._onDidChangeVisibility.event; + private refreshPromise: TPromise = TPromise.as(null); constructor(private viewId: string, private dataProvider: vscode.TreeDataProvider, private proxy: MainThreadTreeViewsShape, private commands: CommandsConverter) { @@ -165,14 +181,18 @@ class ExtHostTreeView extends Disposable { return this.elements.get(treeItemHandle); } - reveal(element: T, options?: { select?: boolean }): TPromise { + reveal(element: T, options?: { select?: boolean, focus?: boolean }): TPromise { + options = options ? options : { select: true, focus: false }; + const select = isUndefinedOrNull(options.select) ? true : options.select; + const focus = isUndefinedOrNull(options.focus) ? false : options.focus; + if (typeof this.dataProvider.getParent !== 'function') { return TPromise.wrapError(new Error(`Required registered TreeDataProvider to implement 'getParent' method to access 'reveal' method`)); } return this.refreshPromise .then(() => this.resolveUnknownParentChain(element)) .then(parentChain => this.resolveTreeNode(element, parentChain[parentChain.length - 1]) - .then(treeNode => this.proxy.$reveal(this.viewId, treeNode.item, parentChain.map(p => p.item), options))); + .then(treeNode => this.proxy.$reveal(this.viewId, treeNode.item, parentChain.map(p => p.item), { select, focus }))); } setExpanded(treeItemHandle: TreeItemHandle, expanded: boolean): void { @@ -189,7 +209,14 @@ class ExtHostTreeView extends Disposable { setSelection(treeItemHandles: TreeItemHandle[]): void { if (!equals(this._selectedHandles, treeItemHandles)) { this._selectedHandles = treeItemHandles; - this._onDidChangeSelection.fire({ selections: this.selectedElements }); + this._onDidChangeSelection.fire({ selection: this.selectedElements }); + } + } + + setVisible(visible: boolean): void { + if (visible !== this._visible) { + this._visible = visible; + this._onDidChangeVisibility.fire({ visible: this._visible }); } } diff --git a/src/vs/workbench/browser/parts/views/customView.ts b/src/vs/workbench/browser/parts/views/customView.ts index 2ada24f3e32aa..eb68d632af74e 100644 --- a/src/vs/workbench/browser/parts/views/customView.ts +++ b/src/vs/workbench/browser/parts/views/customView.ts @@ -192,6 +192,9 @@ export class CustomTreeViewer extends Disposable implements ITreeViewer { private _onDidChangeSelection: Emitter = this._register(new Emitter()); readonly onDidChangeSelection: Event = this._onDidChangeSelection.event; + private _onDidChangeVisibility: Emitter = this._register(new Emitter()); + readonly onDidChangeVisibility: Event = this._onDidChangeVisibility.event; + constructor( private id: string, private container: ViewContainer, @@ -266,6 +269,8 @@ export class CustomTreeViewer extends Disposable implements ITreeViewer { this.elementsToRefresh = []; } } + + this._onDidChangeVisibility.fire(this.isVisible); } focus(): void { @@ -336,13 +341,15 @@ export class CustomTreeViewer extends Disposable implements ITreeViewer { return TPromise.as(null); } - reveal(item: ITreeItem, parentChain: ITreeItem[], options?: { select?: boolean }): TPromise { + reveal(item: ITreeItem, parentChain: ITreeItem[], options?: { select?: boolean, focus?: boolean }): TPromise { if (this.tree && this.isVisible) { - options = options ? options : { select: true }; + options = options ? options : { select: false, focus: false }; + const select = isUndefinedOrNull(options.select) ? false : options.select; + const focus = isUndefinedOrNull(options.focus) ? false : options.focus; + const root: Root = this.tree.getInput(); const promise = root.children ? TPromise.as(null) : this.refresh(); // Refresh if root is not populated return promise.then(() => { - const select = isUndefinedOrNull(options.select) ? true : options.select; var result = TPromise.as(null); parentChain.forEach((e) => { result = result.then(() => this.tree.expand(e)); @@ -352,6 +359,10 @@ export class CustomTreeViewer extends Disposable implements ITreeViewer { if (select) { this.tree.setSelection([item], { source: 'api' }); } + if (focus) { + this.focus(); + this.tree.setFocus(item); + } }); }); } diff --git a/src/vs/workbench/browser/parts/views/viewsViewlet.ts b/src/vs/workbench/browser/parts/views/viewsViewlet.ts index 0f8768f3a5942..e930b4be1fb51 100644 --- a/src/vs/workbench/browser/parts/views/viewsViewlet.ts +++ b/src/vs/workbench/browser/parts/views/viewsViewlet.ts @@ -208,7 +208,9 @@ export abstract class ViewContainerViewlet extends PanelViewlet implements IView } view = this.getView(id); view.setExpanded(true); - view.focus(); + if (focus) { + view.focus(); + } return TPromise.as(view); } diff --git a/src/vs/workbench/common/views.ts b/src/vs/workbench/common/views.ts index b0fc9f381ee46..47d5a9cfadf33 100644 --- a/src/vs/workbench/common/views.ts +++ b/src/vs/workbench/common/views.ts @@ -227,6 +227,8 @@ export interface ITreeViewer extends IDisposable { readonly onDidChangeSelection: Event; + readonly onDidChangeVisibility: Event; + refresh(treeItems?: ITreeItem[]): TPromise; setVisibility(visible: boolean): void; From d0d39157ae19b7f8739189ccd385acea2238fc06 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Tue, 19 Jun 2018 11:36:27 +0200 Subject: [PATCH 3/6] Add doc --- src/vs/vscode.d.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/vs/vscode.d.ts b/src/vs/vscode.d.ts index cc0f3fc912602..d915273447630 100644 --- a/src/vs/vscode.d.ts +++ b/src/vs/vscode.d.ts @@ -6091,6 +6091,9 @@ declare module 'vscode' { } + /** + * The event that is fired when there is a change in [tree view's visibility](#TreeView.visible) + */ export interface TreeViewVisibilityChangeEvent { /** From 5538c6e93f090c2dff6075ebc1fdd4c82c208c7c Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Tue, 19 Jun 2018 11:38:12 +0200 Subject: [PATCH 4/6] update doc --- src/vs/vscode.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/vscode.d.ts b/src/vs/vscode.d.ts index d915273447630..027dec04abc9a 100644 --- a/src/vs/vscode.d.ts +++ b/src/vs/vscode.d.ts @@ -6140,7 +6140,7 @@ declare module 'vscode' { /** * Reveals the given element in the tree view. - * If the tree view is not visible then the element is revealed after the tree view is shown. + * If the tree view is not visible then the tree view is shown and element is revealed. * * By default revealed element is selected and not focused. * In order to not to select, set the option `select` to `false`. From 8af16b52a3bc17ee1a863f80b0a768dd6afee7f6 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Tue, 19 Jun 2018 23:10:30 +0200 Subject: [PATCH 5/6] Introduce double click command --- src/vs/vscode.d.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/vs/vscode.d.ts b/src/vs/vscode.d.ts index 027dec04abc9a..d26e16227147d 100644 --- a/src/vs/vscode.d.ts +++ b/src/vs/vscode.d.ts @@ -6224,10 +6224,15 @@ declare module 'vscode' { tooltip?: string | undefined; /** - * The [command](#Command) which should be run when the tree item is selected. + * The [command](#Command) that should run when the user selects the tree item. */ command?: Command; + /** + * The [command](#Command) that should run when the user double clicks on the tree item. + */ + doubleClickCommand?: Command; + /** * [TreeItemCollapsibleState](#TreeItemCollapsibleState) of the tree item. */ From 71659f2ae88d27cfdf4ea95644d75b53ca424b54 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Wed, 20 Jun 2018 15:39:59 +0200 Subject: [PATCH 6/6] Code review feedback and remove double click command --- src/vs/vscode.d.ts | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/vs/vscode.d.ts b/src/vs/vscode.d.ts index d26e16227147d..1295d0804daf0 100644 --- a/src/vs/vscode.d.ts +++ b/src/vs/vscode.d.ts @@ -6121,7 +6121,7 @@ declare module 'vscode' { /** * Currently selected elements. */ - readonly selection: ReadonlyArray; + readonly selection: T[]; /** * Event that is fired when the [selection](#TreeView.selection) has changed @@ -6224,15 +6224,10 @@ declare module 'vscode' { tooltip?: string | undefined; /** - * The [command](#Command) that should run when the user selects the tree item. + * The [command](#Command) that should be executed when the tree item is selected. */ command?: Command; - /** - * The [command](#Command) that should run when the user double clicks on the tree item. - */ - doubleClickCommand?: Command; - /** * [TreeItemCollapsibleState](#TreeItemCollapsibleState) of the tree item. */