提交 8adb061a 编写于 作者: S Sandeep Somavarapu

#55879 Add expand option to reveal API

上级 c391faf3
......@@ -6499,10 +6499,11 @@ declare module 'vscode' {
* 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`.
* In order to expand the revealed element, set the option `expand` to `true` or `1`. To expand recursively set `expand` to the number of levels to expand.
*
* **NOTE:** [TreeDataProvider](#TreeDataProvider) is required to implement [getParent](#TreeDataProvider.getParent) method to access this API.
*/
reveal(element: T, options?: { select?: boolean, focus?: boolean }): Thenable<void>;
reveal(element: T, options?: { select?: boolean, focus?: boolean, expand?: boolean | number }): Thenable<void>;
}
/**
......
......@@ -6,10 +6,11 @@
import { TPromise } from 'vs/base/common/winjs.base';
import { Disposable } from 'vs/base/common/lifecycle';
import { ExtHostContext, MainThreadTreeViewsShape, ExtHostTreeViewsShape, MainContext, IExtHostContext } from '../node/extHost.protocol';
import { ITreeViewDataProvider, ITreeItem, IViewsService, ITreeViewer, ViewsRegistry, ICustomViewDescriptor } from 'vs/workbench/common/views';
import { ITreeViewDataProvider, ITreeItem, IViewsService, ITreeViewer, ViewsRegistry, ICustomViewDescriptor, IRevealOptions } from 'vs/workbench/common/views';
import { extHostNamedCustomer } from 'vs/workbench/api/electron-browser/extHostCustomers';
import { distinct } from 'vs/base/common/arrays';
import { INotificationService } from 'vs/platform/notification/common/notification';
import { isUndefinedOrNull, isNumber } from 'vs/base/common/types';
@extHostNamedCustomer(MainContext.MainThreadTreeViews)
export class MainThreadTreeViews extends Disposable implements MainThreadTreeViewsShape {
......@@ -40,11 +41,11 @@ export class MainThreadTreeViews extends Disposable implements MainThreadTreeVie
}
}
$reveal(treeViewId: string, item: ITreeItem, parentChain: ITreeItem[], options: { select: boolean, focus: boolean }): Thenable<void> {
$reveal(treeViewId: string, item: ITreeItem, parentChain: ITreeItem[], options: IRevealOptions): Thenable<void> {
return this.viewsService.openView(treeViewId, options.focus)
.then(() => {
const viewer = this.getTreeViewer(treeViewId);
return viewer ? viewer.reveal(item, parentChain, options) : null;
return this.reveal(viewer, this._dataProviders.get(treeViewId), item, parentChain, options);
});
}
......@@ -58,6 +59,42 @@ export class MainThreadTreeViews extends Disposable implements MainThreadTreeVie
return TPromise.as(null);
}
private async reveal(treeViewer: ITreeViewer, dataProvider: TreeViewDataProvider, item: ITreeItem, parentChain: ITreeItem[], options: IRevealOptions): TPromise<void> {
options = options ? options : { select: false, focus: false };
const select = isUndefinedOrNull(options.select) ? false : options.select;
const focus = isUndefinedOrNull(options.focus) ? false : options.focus;
let expand = isNumber(options.expand) ? options.expand : options.expand === true ? 1 : 0;
if (dataProvider.isEmpty()) {
// Refresh if empty
await treeViewer.refresh();
}
for (const parent of parentChain) {
await treeViewer.expand(parent);
}
item = dataProvider.getItem(item.handle);
if (item) {
await treeViewer.reveal(item);
if (select) {
treeViewer.setSelection([item]);
}
if (focus) {
treeViewer.setFocus(item);
}
let itemsToExpand = [item];
for (; itemsToExpand.length > 0 && expand > 0; expand--) {
await treeViewer.expand(itemsToExpand);
itemsToExpand = itemsToExpand.reduce((result, item) => {
item = dataProvider.getItem(item.handle);
if (item && item.children && item.children.length) {
result.push(...item.children);
}
return result;
}, []);
}
}
}
private registerListeners(treeViewId: string, treeViewer: ITreeViewer): void {
this._register(treeViewer.onDidExpandItem(item => this._proxy.$setExpanded(treeViewId, item.handle, true)));
this._register(treeViewer.onDidCollapseItem(item => this._proxy.$setExpanded(treeViewId, item.handle, false)));
......@@ -111,7 +148,7 @@ class TreeViewDataProvider implements ITreeViewDataProvider {
const itemsToRefresh: ITreeItem[] = [];
if (itemsToRefreshByHandle) {
for (const treeItemHandle of Object.keys(itemsToRefreshByHandle)) {
const currentTreeItem = this.itemsMap.get(treeItemHandle);
const currentTreeItem = this.getItem(treeItemHandle);
if (currentTreeItem) { // Refresh only if the item exists
const treeItem = itemsToRefreshByHandle[treeItemHandle];
// Update the current item with refreshed item
......@@ -133,6 +170,14 @@ class TreeViewDataProvider implements ITreeViewDataProvider {
return itemsToRefresh;
}
getItem(treeItemHandle: string): ITreeItem {
return this.itemsMap.get(treeItemHandle);
}
isEmpty(): boolean {
return this.itemsMap.size === 0;
}
private postGetChildren(elements: ITreeItem[]): ITreeItem[] {
const result: ITreeItem[] = [];
if (elements) {
......
......@@ -32,7 +32,7 @@ import { ThemeColor } from 'vs/platform/theme/common/themeService';
import { EndOfLine, IFileOperationOptions, TextEditorLineNumbersStyle } from 'vs/workbench/api/node/extHostTypes';
import { EditorViewColumn } from 'vs/workbench/api/shared/editor';
import { TaskDTO, TaskExecutionDTO, TaskFilterDTO, TaskHandleDTO, TaskProcessEndedDTO, TaskProcessStartedDTO, TaskSystemInfoDTO } from 'vs/workbench/api/shared/tasks';
import { ITreeItem } from 'vs/workbench/common/views';
import { ITreeItem, IRevealOptions } from 'vs/workbench/common/views';
import { IAdapterDescriptor, IConfig, ITerminalSettings } from 'vs/workbench/parts/debug/common/debug';
import { ITextQueryBuilderOptions } from 'vs/workbench/parts/search/common/queryBuilder';
import { TaskSet } from 'vs/workbench/parts/tasks/common/tasks';
......@@ -212,7 +212,7 @@ export interface MainThreadTextEditorsShape extends IDisposable {
export interface MainThreadTreeViewsShape extends IDisposable {
$registerTreeViewDataProvider(treeViewId: string, options: { showCollapseAll: boolean }): void;
$refresh(treeViewId: string, itemsToRefresh?: { [treeItemHandle: string]: ITreeItem }): Thenable<void>;
$reveal(treeViewId: string, treeItem: ITreeItem, parentChain: ITreeItem[], options: { select: boolean, focus: boolean }): Thenable<void>;
$reveal(treeViewId: string, treeItem: ITreeItem, parentChain: ITreeItem[], options: IRevealOptions): Thenable<void>;
}
export interface MainThreadErrorsShape extends IDisposable {
......
......@@ -10,7 +10,7 @@ import { URI } from 'vs/base/common/uri';
import { debounceEvent, Emitter, Event } from 'vs/base/common/event';
import { Disposable } from 'vs/base/common/lifecycle';
import { ExtHostTreeViewsShape, MainThreadTreeViewsShape } from './extHost.protocol';
import { ITreeItem, TreeViewItemHandleArg, ITreeItemLabel } from 'vs/workbench/common/views';
import { ITreeItem, TreeViewItemHandleArg, ITreeItemLabel, IRevealOptions } from 'vs/workbench/common/views';
import { ExtHostCommands, CommandsConverter } from 'vs/workbench/api/node/extHostCommands';
import { asThenable } from 'vs/base/common/async';
import { TreeItemCollapsibleState, ThemeIcon } from 'vs/workbench/api/node/extHostTypes';
......@@ -81,7 +81,7 @@ export class ExtHostTreeViews implements ExtHostTreeViewsShape {
get onDidChangeSelection() { return treeView.onDidChangeSelection; },
get visible() { return treeView.visible; },
get onDidChangeVisibility() { return treeView.onDidChangeVisibility; },
reveal: (element: T, options?: { select?: boolean, focus?: boolean }): Thenable<void> => {
reveal: (element: T, options?: IRevealOptions): Thenable<void> => {
return treeView.reveal(element, options);
},
dispose: () => {
......@@ -209,10 +209,11 @@ class ExtHostTreeView<T> extends Disposable {
return this.elements.get(treeItemHandle);
}
reveal(element: T, options?: { select?: boolean, focus?: boolean }): Promise<void> {
reveal(element: T, options?: IRevealOptions): Promise<void> {
options = options ? options : { select: true, focus: false };
const select = isUndefinedOrNull(options.select) ? true : options.select;
const focus = isUndefinedOrNull(options.focus) ? false : options.focus;
const expand = isUndefinedOrNull(options.expand) ? false : options.expand;
if (typeof this.dataProvider.getParent !== 'function') {
return Promise.reject(new Error(`Required registered TreeDataProvider to implement 'getParent' method to access 'reveal' method`));
......@@ -220,7 +221,7 @@ class ExtHostTreeView<T> extends Disposable {
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), { select, focus })), error => this.logService.error(error));
.then(treeNode => this.proxy.$reveal(this.viewId, treeNode.item, parentChain.map(p => p.item), { select, focus, expand })), error => this.logService.error(error));
}
setExpanded(treeItemHandle: TreeItemHandle, expanded: boolean): void {
......
......@@ -23,7 +23,6 @@ import { IExtensionService } from 'vs/workbench/services/extensions/common/exten
import { IWorkbenchThemeService } from 'vs/workbench/services/themes/common/workbenchThemeService';
import { ICommandService } from 'vs/platform/commands/common/commands';
import * as DOM from 'vs/base/browser/dom';
import { isUndefinedOrNull } from 'vs/base/common/types';
import { IDataSource, ITree, IRenderer, ContextMenuEvent } from 'vs/base/parts/tree/browser/tree';
import { ResourceLabel } from 'vs/workbench/browser/labels';
import { ActionBar, IActionItemProvider, ActionItem } from 'vs/base/browser/ui/actionbar/actionbar';
......@@ -409,32 +408,22 @@ export class CustomTreeViewer extends Disposable implements ITreeViewer {
return Promise.resolve(null);
}
reveal(item: ITreeItem, parentChain: ITreeItem[], options?: { select?: boolean, focus?: boolean }): TPromise<void> {
if (this.dataProvider && this.tree && this.isVisible) {
options = options ? options : { select: false, focus: false };
const select = isUndefinedOrNull(options.select) ? false : options.select;
const focus = isUndefinedOrNull(options.focus) ? false : options.focus;
expand(itemOrItems: ITreeItem | ITreeItem[]): TPromise<void> {
itemOrItems = Array.isArray(itemOrItems) ? itemOrItems : [itemOrItems];
return this.tree.expandAll(itemOrItems);
}
const root: Root = this.tree.getInput();
const promise: Thenable<void> = root.children ? Promise.resolve(null) : this.refresh(); // Refresh if root is not populated
return promise.then(() => {
var result = Promise.resolve(null);
parentChain.forEach((e) => {
result = result.then(() => this.tree.expand(e));
});
return result.then(() => this.tree.reveal(item))
.then(() => {
if (select) {
this.tree.setSelection([item], { source: 'api' });
}
if (focus) {
this.focus();
this.tree.setFocus(item);
}
});
});
}
return Promise.resolve(null);
setSelection(items: ITreeItem[]): void {
this.tree.setSelection(items, { source: 'api' });
}
setFocus(item: ITreeItem): void {
this.focus();
this.tree.setFocus(item);
}
reveal(item: ITreeItem): TPromise<void> {
return this.tree.reveal(item);
}
private activate() {
......
......@@ -265,13 +265,29 @@ export interface ITreeViewer extends IDisposable {
getOptimalWidth(): number;
reveal(item: ITreeItem, parentChain: ITreeItem[], options: { select?: boolean }): TPromise<void>;
reveal(item: ITreeItem): TPromise<void>;
expand(itemOrItems: ITreeItem | ITreeItem[]): TPromise<void>;
setSelection(items: ITreeItem[]): void;
setFocus(item: ITreeItem): void;
getPrimaryActions(): IAction[];
getSecondaryActions(): IAction[];
}
export interface IRevealOptions {
select?: boolean;
focus?: boolean;
expand?: boolean | number;
}
export interface ICustomViewDescriptor extends IViewDescriptor {
readonly treeViewer: ITreeViewer;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册