Skip to content

Commit 678141f

Browse files
committed
remove ITreeNode.parent and ITreeModel.getParentElement
1 parent e8685cb commit 678141f

11 files changed

Lines changed: 112 additions & 120 deletions

File tree

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

Lines changed: 35 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -98,9 +98,11 @@ class TreeNodeListDragAndDrop<T, TFilterData, TRef> implements IListDragAndDrop<
9898
}
9999

100100
if (result.bubble === TreeDragOverBubble.Up) {
101-
const parentNode = targetNode.parent;
102101
const model = this.modelProvider();
103-
const parentIndex = parentNode && model.getListIndex(model.getNodeLocation(parentNode));
102+
const ref = model.getNodeLocation(targetNode);
103+
const parentRef = model.getParentNodeLocation(ref);
104+
const parentNode = model.getNode(parentRef);
105+
const parentIndex = parentRef && model.getListIndex(parentRef);
104106

105107
return this.onDragOver(data, parentNode, parentIndex, originalEvent, false);
106108
}
@@ -155,7 +157,12 @@ function asListOptions<T, TFilterData, TRef>(modelProvider: () => ITreeModel<T,
155157
enableKeyboardNavigation: options.simpleKeyboardNavigation,
156158
ariaProvider: {
157159
getSetSize(node) {
158-
return node.parent!.visibleChildrenCount;
160+
const model = modelProvider();
161+
const ref = model.getNodeLocation(node);
162+
const parentRef = model.getParentNodeLocation(ref);
163+
const parentNode = model.getNode(parentRef);
164+
165+
return parentNode.visibleChildrenCount;
159166
},
160167
getPosInSet(node) {
161168
return node.visibleChildIndex + 1;
@@ -233,7 +240,7 @@ class EventCollection<T> implements Collection<T> {
233240
}
234241
}
235242

236-
class TreeRenderer<T, TFilterData, TTemplateData> implements IListRenderer<ITreeNode<T, TFilterData>, ITreeListTemplateData<TTemplateData>> {
243+
class TreeRenderer<T, TFilterData, TRef, TTemplateData> implements IListRenderer<ITreeNode<T, TFilterData>, ITreeListTemplateData<TTemplateData>> {
237244

238245
private static DefaultIndent = 8;
239246

@@ -251,6 +258,7 @@ class TreeRenderer<T, TFilterData, TTemplateData> implements IListRenderer<ITree
251258

252259
constructor(
253260
private renderer: ITreeRenderer<T, TFilterData, TTemplateData>,
261+
private modelProvider: () => ITreeModel<T, TFilterData, TRef>,
254262
onDidChangeCollapseState: Event<ICollapseStateChangeEvent<T, TFilterData>>,
255263
private activeNodes: Collection<ITreeNode<T, TFilterData>>,
256264
options: ITreeRendererOptions = {}
@@ -380,10 +388,19 @@ class TreeRenderer<T, TFilterData, TTemplateData> implements IListRenderer<ITree
380388
}
381389

382390
const disposableStore = new DisposableStore();
391+
const model = this.modelProvider();
392+
383393
let node = target;
384394

385-
while (node.parent && node.parent.parent) {
386-
const parent = node.parent;
395+
while (true) {
396+
const ref = model.getNodeLocation(node);
397+
const parentRef = model.getParentNodeLocation(ref);
398+
399+
if (!parentRef) {
400+
break;
401+
}
402+
403+
const parent = model.getNode(parentRef);
387404
const guide = $<HTMLDivElement>('.indent-guide', { style: `width: ${this.indent}px` });
388405

389406
if (this.activeParentNodes.has(parent)) {
@@ -411,10 +428,14 @@ class TreeRenderer<T, TFilterData, TTemplateData> implements IListRenderer<ITree
411428
}
412429

413430
const set = new Set<ITreeNode<T, TFilterData>>();
431+
const model = this.modelProvider();
414432

415433
nodes.forEach(node => {
416-
if (node.parent) {
417-
set.add(node.parent);
434+
const ref = model.getNodeLocation(node);
435+
const parentRef = model.getParentNodeLocation(ref);
436+
437+
if (parentRef) {
438+
set.add(model.getNode(parentRef));
418439
}
419440
});
420441

@@ -1136,7 +1157,7 @@ class TreeNodeList<T, TFilterData, TRef> extends List<ITreeNode<T, TFilterData>>
11361157
export abstract class AbstractTree<T, TFilterData, TRef> implements IDisposable {
11371158

11381159
protected view: TreeNodeList<T, TFilterData, TRef>;
1139-
private renderers: TreeRenderer<T, TFilterData, any>[];
1160+
private renderers: TreeRenderer<T, TFilterData, TRef, any>[];
11401161
protected model: ITreeModel<T, TFilterData, TRef>;
11411162
private focus: Trait<T>;
11421163
private selection: Trait<T>;
@@ -1193,7 +1214,7 @@ export abstract class AbstractTree<T, TFilterData, TRef> implements IDisposable
11931214
const activeNodes = new EventCollection(onDidChangeActiveNodes.event);
11941215
this.disposables.push(activeNodes);
11951216

1196-
this.renderers = renderers.map(r => new TreeRenderer<T, TFilterData, any>(r, onDidChangeCollapseStateRelay.event, activeNodes, _options));
1217+
this.renderers = renderers.map(r => new TreeRenderer<T, TFilterData, TRef, any>(r, () => this.model, onDidChangeCollapseStateRelay.event, activeNodes, _options));
11971218
this.disposables.push(...this.renderers);
11981219

11991220
let filter: TypeFilter<T> | undefined;
@@ -1357,7 +1378,9 @@ export abstract class AbstractTree<T, TFilterData, TRef> implements IDisposable
13571378
// Tree navigation
13581379

13591380
getParentElement(location: TRef): T {
1360-
return this.model.getParentElement(location);
1381+
const parentRef = this.model.getParentNodeLocation(location);
1382+
const parentNode = this.model.getNode(parentRef);
1383+
return parentNode.element;
13611384
}
13621385

13631386
getFirstElementChild(location: TRef): T | undefined {
@@ -1509,7 +1532,7 @@ export abstract class AbstractTree<T, TFilterData, TRef> implements IDisposable
15091532
if (!didChange) {
15101533
const parentLocation = this.model.getParentNodeLocation(location);
15111534

1512-
if (parentLocation === null) {
1535+
if (!parentLocation) {
15131536
return;
15141537
}
15151538

@@ -1611,22 +1634,6 @@ class TreeNavigator<T extends NonNullable<any>, TFilterData, TRef> implements IT
16111634
return this.current();
16121635
}
16131636

1614-
parent(): T | null {
1615-
if (this.index < 0 || this.index >= this.view.length) {
1616-
return null;
1617-
}
1618-
1619-
const node = this.view.element(this.index);
1620-
1621-
if (!node.parent) {
1622-
this.index = -1;
1623-
return this.current();
1624-
}
1625-
1626-
this.index = this.model.getListIndex(this.model.getNodeLocation(node.parent));
1627-
return this.current();
1628-
}
1629-
16301637
first(): T | null {
16311638
this.index = 0;
16321639
return this.current();

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

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,6 @@ interface IDataTreeListTemplateData<T> {
6969
class AsyncDataTreeNodeWrapper<TInput, T, TFilterData> implements ITreeNode<TInput | T, TFilterData> {
7070

7171
get element(): T { return this.node.element!.element as T; }
72-
get parent(): ITreeNode<T, TFilterData> | undefined { return this.node.parent && new AsyncDataTreeNodeWrapper(this.node.parent); }
7372
get children(): ITreeNode<T, TFilterData>[] { return this.node.children.map(node => new AsyncDataTreeNodeWrapper(node)); }
7473
get depth(): number { return this.node.depth; }
7574
get visibleChildrenCount(): number { return this.node.visibleChildrenCount; }

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

Lines changed: 8 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -154,8 +154,14 @@ export class CompressedObjectTreeModel<T extends NonNullable<any>, TFilterData e
154154
}
155155

156156
const compressedNode = this.nodes.get(element);
157+
158+
if (!compressedNode) {
159+
throw new Error('Unknown compressed tree node');
160+
}
161+
157162
const node = this.model.getNode(compressedNode) as ITreeNode<ICompressedTreeNode<T>, TFilterData>;
158-
const parent = node.parent!;
163+
const compressedParentNode = this.model.getParentNodeLocation(compressedNode);
164+
const parent = this.model.getNode(compressedParentNode) as ITreeNode<ICompressedTreeNode<T>, TFilterData>;
159165

160166
const decompressedElement = decompress(node);
161167
const splicedElement = splice(decompressedElement, element, Iterator.from(children));
@@ -209,11 +215,6 @@ export class CompressedObjectTreeModel<T extends NonNullable<any>, TFilterData e
209215
return parentNode.elements[parentNode.elements.length - 1];
210216
}
211217

212-
getParentElement(location: T | null): ICompressedTreeNode<T> | null {
213-
const compressedNode = this.getCompressedNode(location);
214-
return this.model.getParentElement(compressedNode);
215-
}
216-
217218
getFirstElementChild(location: T | null): ICompressedTreeNode<T> | null | undefined {
218219
const compressedNode = this.getCompressedNode(location);
219220
return this.model.getFirstElementChild(compressedNode);
@@ -285,8 +286,7 @@ function mapNode<T, TFilterData>(compressedNodeMapper: CompressedNodeMapper<T>,
285286
return {
286287
...node,
287288
element: node.element === null ? null : compressedNodeMapper(node.element),
288-
children: node.children.map(child => mapNode(compressedNodeMapper, child)),
289-
parent: typeof node.parent === 'undefined' ? node.parent : mapNode(compressedNodeMapper, node.parent)
289+
children: node.children.map(child => mapNode(compressedNodeMapper, child))
290290
};
291291
}
292292

@@ -384,16 +384,6 @@ export class CompressibleObjectTreeModel<T extends NonNullable<any>, TFilterData
384384
return this.model.getParentNodeLocation(location);
385385
}
386386

387-
getParentElement(location: T | null): T | null {
388-
const result = this.model.getParentElement(location);
389-
390-
if (result === null) {
391-
return result;
392-
}
393-
394-
return this.elementMapper(result.elements);
395-
}
396-
397387
getFirstElementChild(location: T | null): T | null | undefined {
398388
const result = this.model.getFirstElementChild(location);
399389

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

Lines changed: 30 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,10 @@ import { Emitter, Event, EventBufferer } from 'vs/base/common/event';
99
import { ISequence, Iterator } from 'vs/base/common/iterator';
1010
import { ISpliceable } from 'vs/base/common/sequence';
1111

12-
interface IMutableTreeNode<T, TFilterData> extends ITreeNode<T, TFilterData> {
13-
readonly parent: IMutableTreeNode<T, TFilterData> | undefined;
14-
readonly children: IMutableTreeNode<T, TFilterData>[];
12+
// Exported for tests
13+
export interface IIndexTreeNode<T, TFilterData = void> extends ITreeNode<T, TFilterData> {
14+
readonly parent: IIndexTreeNode<T, TFilterData> | undefined;
15+
readonly children: IIndexTreeNode<T, TFilterData>[];
1516
visibleChildrenCount: number;
1617
visibleChildIndex: number;
1718
collapsible: boolean;
@@ -43,7 +44,7 @@ export class IndexTreeModel<T extends Exclude<any, undefined>, TFilterData = voi
4344

4445
readonly rootRef = [];
4546

46-
private root: IMutableTreeNode<T, TFilterData>;
47+
private root: IIndexTreeNode<T, TFilterData>;
4748
private eventBufferer = new EventBufferer();
4849

4950
private _onDidChangeCollapseState = new Emitter<ICollapseStateChangeEvent<T, TFilterData>>();
@@ -109,7 +110,7 @@ export class IndexTreeModel<T extends Exclude<any, undefined>, TFilterData = voi
109110
}
110111
}
111112

112-
const nodesToInsert: IMutableTreeNode<T, TFilterData>[] = [];
113+
const nodesToInsert: IIndexTreeNode<T, TFilterData>[] = [];
113114
let insertedVisibleChildrenCount = 0;
114115
let renderNodeCount = 0;
115116

@@ -234,7 +235,7 @@ export class IndexTreeModel<T extends Exclude<any, undefined>, TFilterData = voi
234235
return result;
235236
}
236237

237-
private _setListNodeCollapsed(node: IMutableTreeNode<T, TFilterData>, listIndex: number, revealed: boolean, collapsed: boolean, recursive: boolean): boolean {
238+
private _setListNodeCollapsed(node: IIndexTreeNode<T, TFilterData>, listIndex: number, revealed: boolean, collapsed: boolean, recursive: boolean): boolean {
238239
const result = this._setNodeCollapsed(node, collapsed, recursive, false);
239240

240241
if (!revealed || !node.visible) {
@@ -249,7 +250,7 @@ export class IndexTreeModel<T extends Exclude<any, undefined>, TFilterData = voi
249250
return result;
250251
}
251252

252-
private _setNodeCollapsed(node: IMutableTreeNode<T, TFilterData>, collapsed: boolean, recursive: boolean, deep: boolean): boolean {
253+
private _setNodeCollapsed(node: IIndexTreeNode<T, TFilterData>, collapsed: boolean, recursive: boolean, deep: boolean): boolean {
253254
let result = node.collapsible && node.collapsed !== collapsed;
254255

255256
if (node.collapsible) {
@@ -292,13 +293,13 @@ export class IndexTreeModel<T extends Exclude<any, undefined>, TFilterData = voi
292293

293294
private createTreeNode(
294295
treeElement: ITreeElement<T>,
295-
parent: IMutableTreeNode<T, TFilterData>,
296+
parent: IIndexTreeNode<T, TFilterData>,
296297
parentVisibility: TreeVisibility,
297298
revealed: boolean,
298299
treeListElements: ITreeNode<T, TFilterData>[],
299300
onDidCreateNode?: (node: ITreeNode<T, TFilterData>) => void
300-
): IMutableTreeNode<T, TFilterData> {
301-
const node: IMutableTreeNode<T, TFilterData> = {
301+
): IIndexTreeNode<T, TFilterData> {
302+
const node: IIndexTreeNode<T, TFilterData> = {
302303
parent,
303304
element: treeElement.element,
304305
children: [],
@@ -355,7 +356,7 @@ export class IndexTreeModel<T extends Exclude<any, undefined>, TFilterData = voi
355356
return node;
356357
}
357358

358-
private updateNodeAfterCollapseChange(node: IMutableTreeNode<T, TFilterData>): ITreeNode<T, TFilterData>[] {
359+
private updateNodeAfterCollapseChange(node: IIndexTreeNode<T, TFilterData>): ITreeNode<T, TFilterData>[] {
359360
const previousRenderNodeCount = node.renderNodeCount;
360361
const result: ITreeNode<T, TFilterData>[] = [];
361362

@@ -365,7 +366,7 @@ export class IndexTreeModel<T extends Exclude<any, undefined>, TFilterData = voi
365366
return result;
366367
}
367368

368-
private _updateNodeAfterCollapseChange(node: IMutableTreeNode<T, TFilterData>, result: ITreeNode<T, TFilterData>[]): number {
369+
private _updateNodeAfterCollapseChange(node: IIndexTreeNode<T, TFilterData>, result: ITreeNode<T, TFilterData>[]): number {
369370
if (node.visible === false) {
370371
return 0;
371372
}
@@ -383,7 +384,7 @@ export class IndexTreeModel<T extends Exclude<any, undefined>, TFilterData = voi
383384
return node.renderNodeCount;
384385
}
385386

386-
private updateNodeAfterFilterChange(node: IMutableTreeNode<T, TFilterData>): ITreeNode<T, TFilterData>[] {
387+
private updateNodeAfterFilterChange(node: IIndexTreeNode<T, TFilterData>): ITreeNode<T, TFilterData>[] {
387388
const previousRenderNodeCount = node.renderNodeCount;
388389
const result: ITreeNode<T, TFilterData>[] = [];
389390

@@ -393,7 +394,7 @@ export class IndexTreeModel<T extends Exclude<any, undefined>, TFilterData = voi
393394
return result;
394395
}
395396

396-
private _updateNodeAfterFilterChange(node: IMutableTreeNode<T, TFilterData>, parentVisibility: TreeVisibility, result: ITreeNode<T, TFilterData>[], revealed = true): boolean {
397+
private _updateNodeAfterFilterChange(node: IIndexTreeNode<T, TFilterData>, parentVisibility: TreeVisibility, result: ITreeNode<T, TFilterData>[], revealed = true): boolean {
397398
let visibility: TreeVisibility;
398399

399400
if (node !== this.root) {
@@ -447,7 +448,7 @@ export class IndexTreeModel<T extends Exclude<any, undefined>, TFilterData = voi
447448
return node.visible;
448449
}
449450

450-
private _updateAncestorsRenderNodeCount(node: IMutableTreeNode<T, TFilterData> | undefined, diff: number): void {
451+
private _updateAncestorsRenderNodeCount(node: IIndexTreeNode<T, TFilterData> | undefined, diff: number): void {
451452
if (diff === 0) {
452453
return;
453454
}
@@ -459,7 +460,7 @@ export class IndexTreeModel<T extends Exclude<any, undefined>, TFilterData = voi
459460
}
460461
}
461462

462-
private _filterNode(node: IMutableTreeNode<T, TFilterData>, parentVisibility: TreeVisibility): TreeVisibility {
463+
private _filterNode(node: IIndexTreeNode<T, TFilterData>, parentVisibility: TreeVisibility): TreeVisibility {
463464
const result = this.filter ? this.filter.filter(node.element, parentVisibility) : TreeVisibility.Visible;
464465

465466
if (typeof result === 'boolean') {
@@ -475,7 +476,7 @@ export class IndexTreeModel<T extends Exclude<any, undefined>, TFilterData = voi
475476
}
476477

477478
// cheap
478-
private getTreeNode(location: number[], node: IMutableTreeNode<T, TFilterData> = this.root): IMutableTreeNode<T, TFilterData> {
479+
private getTreeNode(location: number[], node: IIndexTreeNode<T, TFilterData> = this.root): IIndexTreeNode<T, TFilterData> {
479480
if (!location || location.length === 0) {
480481
return node;
481482
}
@@ -490,7 +491,7 @@ export class IndexTreeModel<T extends Exclude<any, undefined>, TFilterData = voi
490491
}
491492

492493
// expensive
493-
private getTreeNodeWithListIndex(location: number[]): { node: IMutableTreeNode<T, TFilterData>, listIndex: number, revealed: boolean, visible: boolean } {
494+
private getTreeNodeWithListIndex(location: number[]): { node: IIndexTreeNode<T, TFilterData>, listIndex: number, revealed: boolean, visible: boolean } {
494495
if (location.length === 0) {
495496
return { node: this.root, listIndex: -1, revealed: true, visible: false };
496497
}
@@ -507,7 +508,7 @@ export class IndexTreeModel<T extends Exclude<any, undefined>, TFilterData = voi
507508
return { node, listIndex, revealed, visible: visible && node.visible };
508509
}
509510

510-
private getParentNodeWithListIndex(location: number[], node: IMutableTreeNode<T, TFilterData> = this.root, listIndex: number = 0, revealed = true, visible = true): { parentNode: IMutableTreeNode<T, TFilterData>; listIndex: number; revealed: boolean; visible: boolean; } {
511+
private getParentNodeWithListIndex(location: number[], node: IIndexTreeNode<T, TFilterData> = this.root, listIndex: number = 0, revealed = true, visible = true): { parentNode: IIndexTreeNode<T, TFilterData>; listIndex: number; revealed: boolean; visible: boolean; } {
511512
const [index, ...rest] = location;
512513

513514
if (index < 0 || index > node.children.length) {
@@ -536,27 +537,24 @@ export class IndexTreeModel<T extends Exclude<any, undefined>, TFilterData = voi
536537
// TODO@joao perf!
537538
getNodeLocation(node: ITreeNode<T, TFilterData>): number[] {
538539
const location: number[] = [];
540+
let indexTreeNode = node as IIndexTreeNode<T, TFilterData>; // typing woes
539541

540-
while (node.parent) {
541-
location.push(node.parent.children.indexOf(node));
542-
node = node.parent;
542+
while (indexTreeNode.parent) {
543+
location.push(indexTreeNode.parent.children.indexOf(indexTreeNode));
544+
indexTreeNode = indexTreeNode.parent;
543545
}
544546

545547
return location.reverse();
546548
}
547549

548-
getParentNodeLocation(location: number[]): number[] {
549-
if (location.length <= 1) {
550+
getParentNodeLocation(location: number[]): number[] | undefined {
551+
if (location.length === 0) {
552+
return undefined;
553+
} else if (location.length === 1) {
550554
return [];
555+
} else {
556+
return tail2(location)[0];
551557
}
552-
553-
return tail2(location)[0];
554-
}
555-
556-
getParentElement(location: number[]): T {
557-
const parentLocation = this.getParentNodeLocation(location);
558-
const node = this.getTreeNode(parentLocation);
559-
return node.element;
560558
}
561559

562560
getFirstElementChild(location: number[]): T | undefined {

0 commit comments

Comments
 (0)