Skip to content

Commit 0affcfd

Browse files
committed
avoid data tree expansion in recursive expand
1 parent 1c6050c commit 0affcfd

5 files changed

Lines changed: 38 additions & 25 deletions

File tree

src/vs/base/browser/ui/tree/abstractTree.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import { append, $, toggleClass } from 'vs/base/browser/dom';
1111
import { Event, Relay } from 'vs/base/common/event';
1212
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
1313
import { KeyCode } from 'vs/base/common/keyCodes';
14-
import { ITreeModel, ITreeNode, ITreeRenderer, ITreeEvent, ITreeMouseEvent, ITreeContextMenuEvent, ITreeFilter, ITreeNavigator } from 'vs/base/browser/ui/tree/tree';
14+
import { ITreeModel, ITreeNode, ITreeRenderer, ITreeEvent, ITreeMouseEvent, ITreeContextMenuEvent, ITreeFilter, ITreeNavigator, ICollapseStateChangeEvent } from 'vs/base/browser/ui/tree/tree';
1515
import { ISpliceable } from 'vs/base/common/sequence';
1616

1717
function asListOptions<T, TFilterData>(options?: IAbstractTreeOptions<T, TFilterData>): IListOptions<ITreeNode<T, TFilterData>> | undefined {
@@ -74,11 +74,11 @@ class TreeRenderer<T, TFilterData, TTemplateData> implements IListRenderer<ITree
7474

7575
constructor(
7676
private renderer: ITreeRenderer<T, TFilterData, TTemplateData>,
77-
onDidChangeCollapseState: Event<ITreeNode<T, TFilterData>>
77+
onDidChangeCollapseState: Event<ICollapseStateChangeEvent<T, TFilterData>>
7878
) {
7979
this.templateId = renderer.templateId;
8080

81-
onDidChangeCollapseState(this.onDidChangeNodeTwistieState, this, this.disposables);
81+
Event.map(onDidChangeCollapseState, e => e.node)(this.onDidChangeNodeTwistieState, this, this.disposables);
8282

8383
if (renderer.onDidChangeTwistieState) {
8484
renderer.onDidChangeTwistieState(this.onDidChangeTwistieState, this, this.disposables);
@@ -204,7 +204,7 @@ export abstract class AbstractTree<T, TFilterData, TRef> implements IDisposable
204204
get onDidFocus(): Event<void> { return this.view.onDidFocus; }
205205
get onDidBlur(): Event<void> { return this.view.onDidBlur; }
206206

207-
get onDidChangeCollapseState(): Event<ITreeNode<T, TFilterData>> { return this.model.onDidChangeCollapseState; }
207+
get onDidChangeCollapseState(): Event<ICollapseStateChangeEvent<T, TFilterData>> { return this.model.onDidChangeCollapseState; }
208208
get onDidChangeRenderNodeCount(): Event<ITreeNode<T, TFilterData>> { return this.model.onDidChangeRenderNodeCount; }
209209

210210
get onDidDispose(): Event<void> { return this.view.onDidDispose; }
@@ -217,7 +217,7 @@ export abstract class AbstractTree<T, TFilterData, TRef> implements IDisposable
217217
) {
218218
const treeDelegate = new ComposedTreeDelegate<T, ITreeNode<T, TFilterData>>(delegate);
219219

220-
const onDidChangeCollapseStateRelay = new Relay<ITreeNode<T, TFilterData>>();
220+
const onDidChangeCollapseStateRelay = new Relay<ICollapseStateChangeEvent<T, TFilterData>>();
221221
const treeRenderers = renderers.map(r => new TreeRenderer<T, TFilterData, any>(r, onDidChangeCollapseStateRelay.event));
222222
this.disposables.push(...treeRenderers);
223223

src/vs/base/browser/ui/tree/asyncDataTree.ts

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
import { ComposedTreeDelegate, IAbstractTreeOptions } from 'vs/base/browser/ui/tree/abstractTree';
77
import { ObjectTree, IObjectTreeOptions } from 'vs/base/browser/ui/tree/objectTree';
88
import { IListVirtualDelegate, IIdentityProvider } from 'vs/base/browser/ui/list/list';
9-
import { ITreeElement, ITreeNode, ITreeRenderer, ITreeEvent, ITreeMouseEvent, ITreeContextMenuEvent, ITreeSorter } from 'vs/base/browser/ui/tree/tree';
9+
import { ITreeElement, ITreeNode, ITreeRenderer, ITreeEvent, ITreeMouseEvent, ITreeContextMenuEvent, ITreeSorter, ICollapseStateChangeEvent } from 'vs/base/browser/ui/tree/tree';
1010
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
1111
import { Emitter, Event } from 'vs/base/common/event';
1212
import { timeout, always } from 'vs/base/common/async';
@@ -193,7 +193,6 @@ export class AsyncDataTree<T extends NonNullable<any>, TFilterData = void> imple
193193
get onDidChangeFocus(): Event<ITreeEvent<T>> { return Event.map(this.tree.onDidChangeFocus, asTreeEvent); }
194194
get onDidChangeSelection(): Event<ITreeEvent<T>> { return Event.map(this.tree.onDidChangeSelection, asTreeEvent); }
195195
get onDidOpen(): Event<ITreeEvent<T>> { return Event.map(this.tree.onDidOpen, asTreeEvent); }
196-
get onDidChangeCollapseState(): Event<T> { return Event.map(this.tree.onDidChangeCollapseState, e => e.element!.element!); }
197196

198197
private readonly _onDidResolveChildren = new Emitter<IChildrenResolutionEvent<T>>();
199198
readonly onDidResolveChildren: Event<IChildrenResolutionEvent<T>> = this._onDidResolveChildren.event;
@@ -496,9 +495,13 @@ export class AsyncDataTree<T extends NonNullable<any>, TFilterData = void> imple
496495
}
497496
}
498497

499-
private _onDidChangeCollapseState(treeNode: ITreeNode<IAsyncDataTreeNode<T>, any>): void {
500-
if (!treeNode.collapsed && treeNode.element.state === AsyncDataTreeNodeState.Uninitialized) {
501-
this.refreshNode(treeNode.element, false, ChildrenResolutionReason.Expand);
498+
private _onDidChangeCollapseState({ node, deep }: ICollapseStateChangeEvent<IAsyncDataTreeNode<T>, any>): void {
499+
if (!node.collapsed && node.element.state === AsyncDataTreeNodeState.Uninitialized) {
500+
if (deep) {
501+
this.collapse(node.element.element!);
502+
} else {
503+
this.refreshNode(node.element, false, ChildrenResolutionReason.Expand);
504+
}
502505
}
503506
}
504507

src/vs/base/browser/ui/tree/indexTreeModel.ts

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { ISpliceable } from 'vs/base/common/sequence';
77
import { Iterator, ISequence } from 'vs/base/common/iterator';
88
import { Emitter, Event, EventBufferer } from 'vs/base/common/event';
99
import { tail2 } from 'vs/base/common/arrays';
10-
import { ITreeFilterDataResult, TreeVisibility, ITreeFilter, ITreeModel, ITreeNode, ITreeElement } from 'vs/base/browser/ui/tree/tree';
10+
import { ITreeFilterDataResult, TreeVisibility, ITreeFilter, ITreeModel, ITreeNode, ITreeElement, ICollapseStateChangeEvent } from 'vs/base/browser/ui/tree/tree';
1111

1212
interface IMutableTreeNode<T, TFilterData> extends ITreeNode<T, TFilterData> {
1313
readonly parent: IMutableTreeNode<T, TFilterData> | undefined;
@@ -48,10 +48,10 @@ export class IndexTreeModel<T extends Exclude<any, undefined>, TFilterData = voi
4848
readonly rootRef = [];
4949

5050
private root: IMutableTreeNode<T, TFilterData>;
51-
private eventBufferer = new EventBufferer(); // TODO@joao is this really necessary
51+
private eventBufferer = new EventBufferer();
5252

53-
private _onDidChangeCollapseState = new Emitter<ITreeNode<T, TFilterData>>();
54-
readonly onDidChangeCollapseState: Event<ITreeNode<T, TFilterData>> = this.eventBufferer.wrapEvent(this._onDidChangeCollapseState.event);
53+
private _onDidChangeCollapseState = new Emitter<ICollapseStateChangeEvent<T, TFilterData>>();
54+
readonly onDidChangeCollapseState: Event<ICollapseStateChangeEvent<T, TFilterData>> = this.eventBufferer.wrapEvent(this._onDidChangeCollapseState.event);
5555

5656
private _onDidChangeRenderNodeCount = new Emitter<ITreeNode<T, TFilterData>>();
5757
readonly onDidChangeRenderNodeCount: Event<ITreeNode<T, TFilterData>> = this.eventBufferer.wrapEvent(this._onDidChangeRenderNodeCount.event);
@@ -63,6 +63,8 @@ export class IndexTreeModel<T extends Exclude<any, undefined>, TFilterData = voi
6363
this.collapseByDefault = typeof options.collapseByDefault === 'undefined' ? false : options.collapseByDefault;
6464
this.filter = options.filter;
6565

66+
// this.onDidChangeCollapseState(node => console.log(node.collapsed, node));
67+
6668
this.root = {
6769
parent: undefined,
6870
element: rootElement,
@@ -140,37 +142,40 @@ export class IndexTreeModel<T extends Exclude<any, undefined>, TFilterData = voi
140142
collapsed = !node.collapsed;
141143
}
142144

143-
return this._setCollapsed(node, listIndex, revealed, collapsed, recursive || false);
145+
return this.eventBufferer.bufferEvents(() => {
146+
return this._setCollapsed(node, listIndex, revealed, collapsed!, recursive || false);
147+
});
144148
}
145149

146150
private _setCollapsed(node: IMutableTreeNode<T, TFilterData>, listIndex: number, revealed: boolean, collapsed: boolean, recursive: boolean): boolean {
147-
const result = this._setNodeCollapsed(node, collapsed, recursive);
151+
const result = this._setNodeCollapsed(node, collapsed, recursive, false);
148152

149153
if (!revealed || !node.visible) {
150154
return result;
151155
}
152156

153157
const previousRenderNodeCount = node.renderNodeCount;
154158
const toInsert = this.updateNodeAfterCollapseChange(node);
155-
156159
const deleteCount = previousRenderNodeCount - (listIndex === -1 ? 0 : 1);
157-
158160
this.list.splice(listIndex + 1, deleteCount, toInsert.slice(1));
159-
this._onDidChangeCollapseState.fire(node);
160161

161162
return result;
162163
}
163164

164-
private _setNodeCollapsed(node: IMutableTreeNode<T, TFilterData>, collapsed: boolean, recursive: boolean): boolean {
165+
private _setNodeCollapsed(node: IMutableTreeNode<T, TFilterData>, collapsed: boolean, recursive: boolean, deep: boolean): boolean {
165166
let result = node.collapsible && node.collapsed !== collapsed;
166167

167168
if (node.collapsible) {
168169
node.collapsed = collapsed;
170+
171+
if (result) {
172+
this._onDidChangeCollapseState.fire({ node, deep });
173+
}
169174
}
170175

171176
if (recursive) {
172177
for (const child of node.children) {
173-
result = this._setNodeCollapsed(child, collapsed, true) || result;
178+
result = this._setNodeCollapsed(child, collapsed, true, true) || result;
174179
}
175180
}
176181

src/vs/base/browser/ui/tree/objectTreeModel.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { ISpliceable } from 'vs/base/common/sequence';
77
import { Iterator, ISequence, getSequenceIterator } from 'vs/base/common/iterator';
88
import { IndexTreeModel, IIndexTreeModelOptions } from 'vs/base/browser/ui/tree/indexTreeModel';
99
import { Event } from 'vs/base/common/event';
10-
import { ITreeModel, ITreeNode, ITreeElement, ITreeSorter } from 'vs/base/browser/ui/tree/tree';
10+
import { ITreeModel, ITreeNode, ITreeElement, ITreeSorter, ICollapseStateChangeEvent } from 'vs/base/browser/ui/tree/tree';
1111

1212
export interface IObjectTreeModelOptions<T, TFilterData> extends IIndexTreeModelOptions<T, TFilterData> {
1313
sorter?: ITreeSorter<T>;
@@ -21,14 +21,14 @@ export class ObjectTreeModel<T extends NonNullable<any>, TFilterData extends Non
2121
private nodes = new Map<T | null, ITreeNode<T, TFilterData>>();
2222
private sorter?: ITreeSorter<ITreeElement<T>>;
2323

24-
readonly onDidChangeCollapseState: Event<ITreeNode<T, TFilterData>>;
24+
readonly onDidChangeCollapseState: Event<ICollapseStateChangeEvent<T, TFilterData>>;
2525
readonly onDidChangeRenderNodeCount: Event<ITreeNode<T, TFilterData>>;
2626

2727
get size(): number { return this.nodes.size; }
2828

2929
constructor(list: ISpliceable<ITreeNode<T, TFilterData>>, options: IObjectTreeModelOptions<T, TFilterData> = {}) {
3030
this.model = new IndexTreeModel(list, null, options);
31-
this.onDidChangeCollapseState = this.model.onDidChangeCollapseState as Event<ITreeNode<T, TFilterData>>;
31+
this.onDidChangeCollapseState = this.model.onDidChangeCollapseState as Event<ICollapseStateChangeEvent<T, TFilterData>>;
3232
this.onDidChangeRenderNodeCount = this.model.onDidChangeRenderNodeCount as Event<ITreeNode<T, TFilterData>>;
3333

3434
if (options.sorter) {

src/vs/base/browser/ui/tree/tree.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,9 +89,14 @@ export interface ITreeNode<T, TFilterData = void> {
8989
readonly filterData: TFilterData | undefined;
9090
}
9191

92+
export interface ICollapseStateChangeEvent<T, TFilterData> {
93+
node: ITreeNode<T, TFilterData>;
94+
deep: boolean;
95+
}
96+
9297
export interface ITreeModel<T, TFilterData, TRef> {
9398
readonly rootRef: TRef;
94-
readonly onDidChangeCollapseState: Event<ITreeNode<T, TFilterData>>;
99+
readonly onDidChangeCollapseState: Event<ICollapseStateChangeEvent<T, TFilterData>>;
95100
readonly onDidChangeRenderNodeCount: Event<ITreeNode<T, TFilterData>>;
96101

97102
getListIndex(location: TRef): number;

0 commit comments

Comments
 (0)