mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-16 10:58:30 -05:00
Merge from vscode 817eb6b0c720a4ecbc13c020afbbebfed667aa09 (#7356)
This commit is contained in:
@@ -5,16 +5,16 @@
|
||||
|
||||
import 'vs/css!./media/tree';
|
||||
import { IDisposable, dispose, Disposable, toDisposable, DisposableStore } from 'vs/base/common/lifecycle';
|
||||
import { IListOptions, List, IListStyles, mightProducePrintableCharacter, MouseController } from 'vs/base/browser/ui/list/listWidget';
|
||||
import { IListVirtualDelegate, IListRenderer, IListMouseEvent, IListEvent, IListContextMenuEvent, IListDragAndDrop, IListDragOverReaction, IKeyboardNavigationLabelProvider, IIdentityProvider } from 'vs/base/browser/ui/list/list';
|
||||
import { IListOptions, List, IListStyles, MouseController, DefaultKeyboardNavigationDelegate } from 'vs/base/browser/ui/list/listWidget';
|
||||
import { IListVirtualDelegate, IListRenderer, IListMouseEvent, IListEvent, IListContextMenuEvent, IListDragAndDrop, IListDragOverReaction, IKeyboardNavigationLabelProvider, IIdentityProvider, IKeyboardNavigationDelegate } from 'vs/base/browser/ui/list/list';
|
||||
import { append, $, toggleClass, getDomNodePagePosition, removeClass, addClass, hasClass, hasParentWithClass, createStyleSheet, clearNode } from 'vs/base/browser/dom';
|
||||
import { Event, Relay, Emitter, EventBufferer } from 'vs/base/common/event';
|
||||
import { StandardKeyboardEvent, IKeyboardEvent } from 'vs/base/browser/keyboardEvent';
|
||||
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
|
||||
import { KeyCode } from 'vs/base/common/keyCodes';
|
||||
import { ITreeModel, ITreeNode, ITreeRenderer, ITreeEvent, ITreeMouseEvent, ITreeContextMenuEvent, ITreeFilter, ITreeNavigator, ICollapseStateChangeEvent, ITreeDragAndDrop, TreeDragOverBubble, TreeVisibility, TreeFilterResult, ITreeModelSpliceEvent, TreeMouseEventTarget } from 'vs/base/browser/ui/tree/tree';
|
||||
import { ISpliceable } from 'vs/base/common/sequence';
|
||||
import { IDragAndDropData, StaticDND, DragAndDropData } from 'vs/base/browser/dnd';
|
||||
import { range, equals, distinctES6 } from 'vs/base/common/arrays';
|
||||
import { range, equals, distinctES6, fromSet } from 'vs/base/common/arrays';
|
||||
import { ElementsDragAndDropData } from 'vs/base/browser/ui/list/listView';
|
||||
import { domEvent } from 'vs/base/browser/event';
|
||||
import { fuzzyScore, FuzzyScore } from 'vs/base/common/filters';
|
||||
@@ -567,7 +567,7 @@ class TypeFilterController<T, TFilterData> implements IDisposable {
|
||||
private _empty: boolean = false;
|
||||
get empty(): boolean { return this._empty; }
|
||||
|
||||
private _onDidChangeEmptyState = new Emitter<boolean>();
|
||||
private readonly _onDidChangeEmptyState = new Emitter<boolean>();
|
||||
readonly onDidChangeEmptyState: Event<boolean> = Event.latch(this._onDidChangeEmptyState.event);
|
||||
|
||||
private positionClassName = 'ne';
|
||||
@@ -581,7 +581,7 @@ class TypeFilterController<T, TFilterData> implements IDisposable {
|
||||
private automaticKeyboardNavigation = true;
|
||||
private triggered = false;
|
||||
|
||||
private _onDidChangePattern = new Emitter<string>();
|
||||
private readonly _onDidChangePattern = new Emitter<string>();
|
||||
readonly onDidChangePattern = this._onDidChangePattern.event;
|
||||
|
||||
private enabledDisposables: IDisposable[] = [];
|
||||
@@ -592,7 +592,7 @@ class TypeFilterController<T, TFilterData> implements IDisposable {
|
||||
model: ITreeModel<T, TFilterData, any>,
|
||||
private view: List<ITreeNode<T, TFilterData>>,
|
||||
private filter: TypeFilter<T>,
|
||||
private keyboardNavigationLabelProvider: IKeyboardNavigationLabelProvider<T>
|
||||
private keyboardNavigationDelegate: IKeyboardNavigationDelegate
|
||||
) {
|
||||
this.domNode = $(`.monaco-list-type-filter.${this.positionClassName}`);
|
||||
this.domNode.draggable = true;
|
||||
@@ -658,13 +658,12 @@ class TypeFilterController<T, TFilterData> implements IDisposable {
|
||||
return;
|
||||
}
|
||||
|
||||
const isPrintableCharEvent = this.keyboardNavigationLabelProvider.mightProducePrintableCharacter ? (e: IKeyboardEvent) => this.keyboardNavigationLabelProvider.mightProducePrintableCharacter!(e) : (e: IKeyboardEvent) => mightProducePrintableCharacter(e);
|
||||
const onKeyDown = Event.chain(domEvent(this.view.getHTMLElement(), 'keydown'))
|
||||
.filter(e => !isInputElement(e.target as HTMLElement) || e.target === this.filterOnTypeDomNode)
|
||||
.map(e => new StandardKeyboardEvent(e))
|
||||
.filter(this.keyboardNavigationEventFilter || (() => true))
|
||||
.filter(() => this.automaticKeyboardNavigation || this.triggered)
|
||||
.filter(e => isPrintableCharEvent(e) || ((this.pattern.length > 0 || this.triggered) && ((e.keyCode === KeyCode.Escape || e.keyCode === KeyCode.Backspace) && !e.altKey && !e.ctrlKey && !e.metaKey) || (e.keyCode === KeyCode.Backspace && (isMacintosh ? (e.altKey && !e.metaKey) : e.ctrlKey) && !e.shiftKey)))
|
||||
.filter(e => this.keyboardNavigationDelegate.mightProducePrintableCharacter(e) || ((this.pattern.length > 0 || this.triggered) && ((e.keyCode === KeyCode.Escape || e.keyCode === KeyCode.Backspace) && !e.altKey && !e.ctrlKey && !e.metaKey) || (e.keyCode === KeyCode.Backspace && (isMacintosh ? (e.altKey && !e.metaKey) : e.ctrlKey) && !e.shiftKey)))
|
||||
.forEach(e => { e.stopPropagation(); e.preventDefault(); })
|
||||
.event;
|
||||
|
||||
@@ -935,7 +934,7 @@ class Trait<T> {
|
||||
private nodes: ITreeNode<T, any>[] = [];
|
||||
private elements: T[] | undefined;
|
||||
|
||||
private _onDidChange = new Emitter<ITreeEvent<T>>();
|
||||
private readonly _onDidChange = new Emitter<ITreeEvent<T>>();
|
||||
readonly onDidChange = this._onDidChange.event;
|
||||
|
||||
private _nodeSet: Set<ITreeNode<T, any>> | undefined;
|
||||
@@ -1189,6 +1188,7 @@ export abstract class AbstractTree<T, TFilterData, TRef> implements IDisposable
|
||||
get onDidChangeFocus(): Event<ITreeEvent<T>> { return this.eventBufferer.wrapEvent(this.focus.onDidChange); }
|
||||
get onDidChangeSelection(): Event<ITreeEvent<T>> { return this.eventBufferer.wrapEvent(this.selection.onDidChange); }
|
||||
get onDidOpen(): Event<ITreeEvent<T>> { return Event.map(this.view.onDidOpen, asTreeEvent); }
|
||||
get onDidPin(): Event<ITreeEvent<T>> { return Event.map(this.view.onDidPin, asTreeEvent); }
|
||||
|
||||
get onMouseClick(): Event<ITreeMouseEvent<T>> { return Event.map(this.view.onMouseClick, asTreeMouseEvent); }
|
||||
get onMouseDblClick(): Event<ITreeMouseEvent<T>> { return Event.map(this.view.onMouseDblClick, asTreeMouseEvent); }
|
||||
@@ -1204,7 +1204,7 @@ export abstract class AbstractTree<T, TFilterData, TRef> implements IDisposable
|
||||
get onDidChangeCollapseState(): Event<ICollapseStateChangeEvent<T, TFilterData>> { return this.model.onDidChangeCollapseState; }
|
||||
get onDidChangeRenderNodeCount(): Event<ITreeNode<T, TFilterData>> { return this.model.onDidChangeRenderNodeCount; }
|
||||
|
||||
private _onWillRefilter = new Emitter<void>();
|
||||
private readonly _onWillRefilter = new Emitter<void>();
|
||||
readonly onWillRefilter: Event<void> = this._onWillRefilter.event;
|
||||
|
||||
get filterOnType(): boolean { return !!this._options.filterOnType; }
|
||||
@@ -1213,7 +1213,7 @@ export abstract class AbstractTree<T, TFilterData, TRef> implements IDisposable
|
||||
get openOnSingleClick(): boolean { return typeof this._options.openOnSingleClick === 'undefined' ? true : this._options.openOnSingleClick; }
|
||||
get expandOnlyOnTwistieClick(): boolean | ((e: T) => boolean) { return typeof this._options.expandOnlyOnTwistieClick === 'undefined' ? false : this._options.expandOnlyOnTwistieClick; }
|
||||
|
||||
private _onDidUpdateOptions = new Emitter<IAbstractTreeOptions<T, TFilterData>>();
|
||||
private readonly _onDidUpdateOptions = new Emitter<IAbstractTreeOptions<T, TFilterData>>();
|
||||
readonly onDidUpdateOptions: Event<IAbstractTreeOptions<T, TFilterData>> = this._onDidUpdateOptions.event;
|
||||
|
||||
get onDidDispose(): Event<void> { return this.view.onDidDispose; }
|
||||
@@ -1228,7 +1228,7 @@ export abstract class AbstractTree<T, TFilterData, TRef> implements IDisposable
|
||||
const treeDelegate = new ComposedTreeDelegate<T, ITreeNode<T, TFilterData>>(delegate);
|
||||
|
||||
const onDidChangeCollapseStateRelay = new Relay<ICollapseStateChangeEvent<T, TFilterData>>();
|
||||
const onDidChangeActiveNodes = new Relay<ITreeNode<T, TFilterData>[]>();
|
||||
const onDidChangeActiveNodes = new Emitter<ITreeNode<T, TFilterData>[]>();
|
||||
const activeNodes = new EventCollection(onDidChangeActiveNodes.event);
|
||||
this.disposables.push(activeNodes);
|
||||
|
||||
@@ -1251,11 +1251,23 @@ export abstract class AbstractTree<T, TFilterData, TRef> implements IDisposable
|
||||
onDidChangeCollapseStateRelay.input = this.model.onDidChangeCollapseState;
|
||||
|
||||
this.model.onDidSplice(e => {
|
||||
this.focus.onDidModelSplice(e);
|
||||
this.selection.onDidModelSplice(e);
|
||||
}, null, this.disposables);
|
||||
this.eventBufferer.bufferEvents(() => {
|
||||
this.focus.onDidModelSplice(e);
|
||||
this.selection.onDidModelSplice(e);
|
||||
});
|
||||
|
||||
onDidChangeActiveNodes.input = Event.map(Event.any<any>(this.focus.onDidChange, this.selection.onDidChange, this.model.onDidSplice), () => [...this.focus.getNodes(), ...this.selection.getNodes()]);
|
||||
const set = new Set<ITreeNode<T, TFilterData>>();
|
||||
|
||||
for (const node of this.focus.getNodes()) {
|
||||
set.add(node);
|
||||
}
|
||||
|
||||
for (const node of this.selection.getNodes()) {
|
||||
set.add(node);
|
||||
}
|
||||
|
||||
onDidChangeActiveNodes.fire(fromSet(set));
|
||||
}, null, this.disposables);
|
||||
|
||||
if (_options.keyboardSupport !== false) {
|
||||
const onKeyDown = Event.chain(this.view.onKeyDown)
|
||||
@@ -1268,7 +1280,8 @@ export abstract class AbstractTree<T, TFilterData, TRef> implements IDisposable
|
||||
}
|
||||
|
||||
if (_options.keyboardNavigationLabelProvider) {
|
||||
this.typeFilterController = new TypeFilterController(this, this.model, this.view, filter!, _options.keyboardNavigationLabelProvider);
|
||||
const delegate = _options.keyboardNavigationDelegate || DefaultKeyboardNavigationDelegate;
|
||||
this.typeFilterController = new TypeFilterController(this, this.model, this.view, filter!, delegate);
|
||||
this.focusNavigationFilter = node => this.typeFilterController!.shouldAllowFocus(node);
|
||||
this.disposables.push(this.typeFilterController!);
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { ComposedTreeDelegate, IAbstractTreeOptions, IAbstractTreeOptionsUpdate } from 'vs/base/browser/ui/tree/abstractTree';
|
||||
import { ObjectTree, IObjectTreeOptions, CompressibleObjectTree, ICompressibleTreeRenderer } from 'vs/base/browser/ui/tree/objectTree';
|
||||
import { ObjectTree, IObjectTreeOptions, CompressibleObjectTree, ICompressibleTreeRenderer, ICompressibleKeyboardNavigationLabelProvider, ICompressibleObjectTreeOptions } from 'vs/base/browser/ui/tree/objectTree';
|
||||
import { IListVirtualDelegate, IIdentityProvider, IListDragAndDrop, IListDragOverReaction } from 'vs/base/browser/ui/list/list';
|
||||
import { ITreeElement, ITreeNode, ITreeRenderer, ITreeEvent, ITreeMouseEvent, ITreeContextMenuEvent, ITreeSorter, ICollapseStateChangeEvent, IAsyncDataSource, ITreeDragAndDrop, TreeError, WeakMapper } from 'vs/base/browser/ui/tree/tree';
|
||||
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
|
||||
@@ -1010,6 +1010,24 @@ export interface ITreeCompressionDelegate<T> {
|
||||
isIncompressible(element: T): boolean;
|
||||
}
|
||||
|
||||
function asCompressibleObjectTreeOptions<TInput, T, TFilterData>(options?: ICompressibleAsyncDataTreeOptions<T, TFilterData>): ICompressibleObjectTreeOptions<IAsyncDataTreeNode<TInput, T>, TFilterData> | undefined {
|
||||
const objectTreeOptions = options && asObjectTreeOptions(options);
|
||||
|
||||
return objectTreeOptions && {
|
||||
...objectTreeOptions,
|
||||
keyboardNavigationLabelProvider: objectTreeOptions.keyboardNavigationLabelProvider && {
|
||||
...objectTreeOptions.keyboardNavigationLabelProvider,
|
||||
getCompressedNodeKeyboardNavigationLabel(els) {
|
||||
return options!.keyboardNavigationLabelProvider!.getCompressedNodeKeyboardNavigationLabel(els.map(e => e.element as T));
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export interface ICompressibleAsyncDataTreeOptions<T, TFilterData = void> extends IAsyncDataTreeOptions<T, TFilterData> {
|
||||
readonly keyboardNavigationLabelProvider?: ICompressibleKeyboardNavigationLabelProvider<T>;
|
||||
}
|
||||
|
||||
export class CompressibleAsyncDataTree<TInput, T, TFilterData = void> extends AsyncDataTree<TInput, T, TFilterData> {
|
||||
|
||||
protected readonly compressibleNodeMapper: CompressibleAsyncDataTreeNodeMapper<TInput, T, TFilterData> = new WeakMapper(node => new CompressibleAsyncDataTreeNodeWrapper(node));
|
||||
@@ -1031,11 +1049,11 @@ export class CompressibleAsyncDataTree<TInput, T, TFilterData = void> extends As
|
||||
container: HTMLElement,
|
||||
delegate: IListVirtualDelegate<T>,
|
||||
renderers: ICompressibleTreeRenderer<T, TFilterData, any>[],
|
||||
options: IAsyncDataTreeOptions<T, TFilterData>
|
||||
options: ICompressibleAsyncDataTreeOptions<T, TFilterData>
|
||||
): ObjectTree<IAsyncDataTreeNode<TInput, T>, TFilterData> {
|
||||
const objectTreeDelegate = new ComposedTreeDelegate<TInput | T, IAsyncDataTreeNode<TInput, T>>(delegate);
|
||||
const objectTreeRenderers = renderers.map(r => new CompressibleAsyncDataTreeRenderer(r, this.nodeMapper, () => this.compressibleNodeMapper, this._onDidChangeNodeSlowState.event));
|
||||
const objectTreeOptions = asObjectTreeOptions<TInput, T, TFilterData>(options) || {};
|
||||
const objectTreeOptions = asCompressibleObjectTreeOptions<TInput, T, TFilterData>(options) || {};
|
||||
|
||||
return new CompressibleObjectTree(user, container, objectTreeDelegate, objectTreeRenderers, objectTreeOptions);
|
||||
}
|
||||
|
||||
@@ -336,7 +336,7 @@ function mapOptions<T, TFilterData>(compressedNodeUnwrapper: CompressedNodeUnwra
|
||||
...options,
|
||||
sorter: options.sorter && {
|
||||
compare(node: ICompressedTreeNode<T>, otherNode: ICompressedTreeNode<T>): number {
|
||||
return options.sorter!.compare(compressedNodeUnwrapper(node), compressedNodeUnwrapper(otherNode));
|
||||
return options.sorter!.compare(node.elements[0], otherNode.elements[0]);
|
||||
}
|
||||
},
|
||||
identityProvider: options.identityProvider && {
|
||||
|
||||
@@ -162,9 +162,10 @@ export class DataTree<TInput, T, TFilterData = void> extends AbstractTree<T | nu
|
||||
const children = this.dataSource.getChildren(element);
|
||||
const elements = Iterator.map<any, ITreeElement<T>>(Iterator.fromArray(children), element => {
|
||||
const { elements: children, size } = this.iterate(element, isCollapsed);
|
||||
const collapsible = this.dataSource.hasChildren ? this.dataSource.hasChildren(element) : undefined;
|
||||
const collapsed = size === 0 ? undefined : (isCollapsed && isCollapsed(element));
|
||||
|
||||
return { element, children, collapsed };
|
||||
return { element, children, collapsible, collapsed };
|
||||
});
|
||||
|
||||
return { elements, size: children.length };
|
||||
|
||||
@@ -62,17 +62,17 @@ export class IndexTreeModel<T extends Exclude<any, undefined>, TFilterData = voi
|
||||
private root: IIndexTreeNode<T, TFilterData>;
|
||||
private eventBufferer = new EventBufferer();
|
||||
|
||||
private _onDidChangeCollapseState = new Emitter<ICollapseStateChangeEvent<T, TFilterData>>();
|
||||
private readonly _onDidChangeCollapseState = new Emitter<ICollapseStateChangeEvent<T, TFilterData>>();
|
||||
readonly onDidChangeCollapseState: Event<ICollapseStateChangeEvent<T, TFilterData>> = this.eventBufferer.wrapEvent(this._onDidChangeCollapseState.event);
|
||||
|
||||
private _onDidChangeRenderNodeCount = new Emitter<ITreeNode<T, TFilterData>>();
|
||||
private readonly _onDidChangeRenderNodeCount = new Emitter<ITreeNode<T, TFilterData>>();
|
||||
readonly onDidChangeRenderNodeCount: Event<ITreeNode<T, TFilterData>> = this.eventBufferer.wrapEvent(this._onDidChangeRenderNodeCount.event);
|
||||
|
||||
private collapseByDefault: boolean;
|
||||
private filter?: ITreeFilter<T, TFilterData>;
|
||||
private autoExpandSingleChildren: boolean;
|
||||
|
||||
private _onDidSplice = new Emitter<ITreeModelSpliceEvent<T, TFilterData>>();
|
||||
private readonly _onDidSplice = new Emitter<ITreeModelSpliceEvent<T, TFilterData>>();
|
||||
readonly onDidSplice = this._onDidSplice.event;
|
||||
|
||||
constructor(
|
||||
@@ -169,7 +169,7 @@ export class IndexTreeModel<T extends Exclude<any, undefined>, TFilterData = voi
|
||||
parentNode.visibleChildrenCount += insertedVisibleChildrenCount - deletedVisibleChildrenCount;
|
||||
|
||||
if (revealed && visible) {
|
||||
const visibleDeleteCount = deletedNodes.reduce((r, node) => r + node.renderNodeCount, 0);
|
||||
const visibleDeleteCount = deletedNodes.reduce((r, node) => r + (node.visible ? node.renderNodeCount : 0), 0);
|
||||
|
||||
this._updateAncestorsRenderNodeCount(parentNode, renderNodeCount - visibleDeleteCount);
|
||||
this.list.splice(listIndex, visibleDeleteCount, treeListElementsToInsert);
|
||||
|
||||
@@ -8,9 +8,10 @@ import { AbstractTree, IAbstractTreeOptions } from 'vs/base/browser/ui/tree/abst
|
||||
import { ISpliceable } from 'vs/base/common/sequence';
|
||||
import { ITreeNode, ITreeModel, ITreeElement, ITreeRenderer, ITreeSorter, ICollapseStateChangeEvent } from 'vs/base/browser/ui/tree/tree';
|
||||
import { ObjectTreeModel, IObjectTreeModel } from 'vs/base/browser/ui/tree/objectTreeModel';
|
||||
import { IListVirtualDelegate } from 'vs/base/browser/ui/list/list';
|
||||
import { IListVirtualDelegate, IKeyboardNavigationLabelProvider } from 'vs/base/browser/ui/list/list';
|
||||
import { Event } from 'vs/base/common/event';
|
||||
import { CompressibleObjectTreeModel, ElementMapper, ICompressedTreeNode, ICompressedTreeElement } from 'vs/base/browser/ui/tree/compressedObjectTreeModel';
|
||||
import { memoize } from 'vs/base/common/decorators';
|
||||
|
||||
export interface IObjectTreeOptions<T, TFilterData = void> extends IAbstractTreeOptions<T, TFilterData> {
|
||||
sorter?: ITreeSorter<T>;
|
||||
@@ -77,9 +78,12 @@ class CompressibleRenderer<T, TFilterData, TTemplateData> implements ITreeRender
|
||||
readonly templateId: string;
|
||||
readonly onDidChangeTwistieState: Event<T> | undefined;
|
||||
|
||||
compressedTreeNodeProvider: ICompressedTreeNodeProvider<T, TFilterData>;
|
||||
@memoize
|
||||
private get compressedTreeNodeProvider(): ICompressedTreeNodeProvider<T, TFilterData> {
|
||||
return this._compressedTreeNodeProvider();
|
||||
}
|
||||
|
||||
constructor(private renderer: ICompressibleTreeRenderer<T, TFilterData, TTemplateData>) {
|
||||
constructor(private _compressedTreeNodeProvider: () => ICompressedTreeNodeProvider<T, TFilterData>, private renderer: ICompressibleTreeRenderer<T, TFilterData, TTemplateData>) {
|
||||
this.templateId = renderer.templateId;
|
||||
|
||||
if (renderer.onDidChangeTwistieState) {
|
||||
@@ -127,7 +131,38 @@ class CompressibleRenderer<T, TFilterData, TTemplateData> implements ITreeRender
|
||||
}
|
||||
}
|
||||
|
||||
export class CompressibleObjectTree<T extends NonNullable<any>, TFilterData = void> extends ObjectTree<T, TFilterData> {
|
||||
export interface ICompressibleKeyboardNavigationLabelProvider<T> extends IKeyboardNavigationLabelProvider<T> {
|
||||
getCompressedNodeKeyboardNavigationLabel(elements: T[]): { toString(): string | undefined; } | undefined;
|
||||
}
|
||||
|
||||
export interface ICompressibleObjectTreeOptions<T, TFilterData = void> extends IObjectTreeOptions<T, TFilterData> {
|
||||
readonly keyboardNavigationLabelProvider?: ICompressibleKeyboardNavigationLabelProvider<T>;
|
||||
}
|
||||
|
||||
function asObjectTreeOptions<T, TFilterData>(compressedTreeNodeProvider: () => ICompressedTreeNodeProvider<T, TFilterData>, options?: ICompressibleObjectTreeOptions<T, TFilterData>): IObjectTreeOptions<T, TFilterData> | undefined {
|
||||
return options && {
|
||||
...options,
|
||||
keyboardNavigationLabelProvider: options.keyboardNavigationLabelProvider && {
|
||||
getKeyboardNavigationLabel(e: T) {
|
||||
let compressedTreeNode: ITreeNode<ICompressedTreeNode<T>, TFilterData>;
|
||||
|
||||
try {
|
||||
compressedTreeNode = compressedTreeNodeProvider().getCompressedTreeNode(e);
|
||||
} catch {
|
||||
return options.keyboardNavigationLabelProvider!.getKeyboardNavigationLabel(e);
|
||||
}
|
||||
|
||||
if (compressedTreeNode.element.elements.length === 1) {
|
||||
return options.keyboardNavigationLabelProvider!.getKeyboardNavigationLabel(e);
|
||||
} else {
|
||||
return options.keyboardNavigationLabelProvider!.getCompressedNodeKeyboardNavigationLabel(compressedTreeNode.element.elements);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export class CompressibleObjectTree<T extends NonNullable<any>, TFilterData = void> extends ObjectTree<T, TFilterData> implements ICompressedTreeNodeProvider<T, TFilterData> {
|
||||
|
||||
protected model: CompressibleObjectTreeModel<T, TFilterData>;
|
||||
|
||||
@@ -136,11 +171,11 @@ export class CompressibleObjectTree<T extends NonNullable<any>, TFilterData = vo
|
||||
container: HTMLElement,
|
||||
delegate: IListVirtualDelegate<T>,
|
||||
renderers: ICompressibleTreeRenderer<T, TFilterData, any>[],
|
||||
options: IObjectTreeOptions<T, TFilterData> = {}
|
||||
options: ICompressibleObjectTreeOptions<T, TFilterData> = {}
|
||||
) {
|
||||
const compressibleRenderers = renderers.map(r => new CompressibleRenderer(r));
|
||||
super(user, container, delegate, compressibleRenderers, options);
|
||||
compressibleRenderers.forEach(r => r.compressedTreeNodeProvider = this);
|
||||
const compressedTreeNodeProvider = () => this;
|
||||
const compressibleRenderers = renderers.map(r => new CompressibleRenderer(compressedTreeNodeProvider, r));
|
||||
super(user, container, delegate, compressibleRenderers, asObjectTreeOptions(compressedTreeNodeProvider, options));
|
||||
}
|
||||
|
||||
setChildren(element: T | null, children?: ISequence<ICompressedTreeElement<T>>): void {
|
||||
|
||||
@@ -9,6 +9,7 @@ import { IndexTreeModel, IIndexTreeModelOptions } from 'vs/base/browser/ui/tree/
|
||||
import { Event } from 'vs/base/common/event';
|
||||
import { ITreeModel, ITreeNode, ITreeElement, ITreeSorter, ICollapseStateChangeEvent, ITreeModelSpliceEvent, TreeError } from 'vs/base/browser/ui/tree/tree';
|
||||
import { IIdentityProvider } from 'vs/base/browser/ui/list/list';
|
||||
import { mergeSort } from 'vs/base/common/arrays';
|
||||
|
||||
export type ITreeNodeCallback<T, TFilterData> = (node: ITreeNode<T, TFilterData>) => void;
|
||||
|
||||
@@ -123,7 +124,7 @@ export class ObjectTreeModel<T extends NonNullable<any>, TFilterData extends Non
|
||||
let iterator = elements ? getSequenceIterator(elements) : Iterator.empty<ITreeElement<T>>();
|
||||
|
||||
if (this.sorter) {
|
||||
iterator = Iterator.fromArray(Iterator.collect(iterator).sort(this.sorter.compare.bind(this.sorter)));
|
||||
iterator = Iterator.fromArray(mergeSort(Iterator.collect(iterator), this.sorter.compare.bind(this.sorter)));
|
||||
}
|
||||
|
||||
return Iterator.map(iterator, treeElement => {
|
||||
|
||||
@@ -164,6 +164,7 @@ export interface ITreeNavigator<T> {
|
||||
}
|
||||
|
||||
export interface IDataSource<TInput, T> {
|
||||
hasChildren?(element: TInput | T): boolean;
|
||||
getChildren(element: TInput | T): T[];
|
||||
}
|
||||
|
||||
|
||||
@@ -22,4 +22,4 @@ export class CollapseAllAction<TInput, T, TFilterData = void> extends Action {
|
||||
|
||||
return Promise.resolve();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user