提交 dd5e23bf 编写于 作者: J Joao Moreno

CollapsibleTreeModel

上级 28e21308
......@@ -7,6 +7,8 @@
import { ISpliceable } from 'vs/base/common/sequence';
import { IIterator, map, collect, forEach, iter } from 'vs/base/common/iterator';
import { last } from 'vs/base/common/arrays';
import { Tree } from 'vs/base/common/tree';
/**
* TODO:
......@@ -73,10 +75,10 @@ class TreeNode<T> implements ITreeListElement<T> {
}
}
function asTreeElement<T>(node: TreeNode<T>): ITreeElement<T> {
function createTreeElementFromTreeNode<T>(node: TreeNode<T>): ITreeElement<T> {
return {
element: node.element,
children: map(iter(node.children), asTreeElement)
children: map(iter(node.children), createTreeElementFromTreeNode)
};
}
......@@ -86,18 +88,18 @@ export class TreeModel<T> {
constructor(private spliceable: ISpliceable<ITreeListElement<T>>) { }
splice(start: number[], deleteCount: number, toInsert: IIterator<ITreeElement<T>>): IIterator<ITreeElement<T>> {
if (start.length === 0) {
splice(location: number[], deleteCount: number, toInsert: IIterator<ITreeElement<T>>): IIterator<ITreeElement<T>> {
if (location.length === 0) {
throw new Error('Invalid tree location');
}
const { parentNode, parentListIndex } = this.findParentNode(start);
const lastIndex = start[start.length - 1];
const { listDeleteCount, listElements, deletedNodes } = parentNode.splice(lastIndex, deleteCount, toInsert);
const { parentNode, parentListIndex } = this.findParentNode(location);
const index = last(location);
const { listDeleteCount, listElements, deletedNodes } = parentNode.splice(index, deleteCount, toInsert);
this.spliceable.splice(parentListIndex + lastIndex, listDeleteCount, listElements);
this.spliceable.splice(parentListIndex + index, listDeleteCount, listElements);
return map(iter(deletedNodes), asTreeElement);
return map(iter(deletedNodes), createTreeElementFromTreeNode);
}
private findParentNode(location: number[], node: TreeNode<T> = this.root, listIndex: number = 0): { parentNode: TreeNode<T>; parentListIndex: number } {
......@@ -116,3 +118,36 @@ export class TreeModel<T> {
return this.findParentNode(rest, node.children[i], listIndex + 1);
}
}
interface ICollapsibleElement<T> {
collapsed: boolean;
element: T;
}
export type ICollapsibleTreeElement<T> = ITreeElement<ICollapsibleElement<T>>;
export type ICollapsibleTreeListElement<T> = ITreeListElement<ICollapsibleElement<T>>;
export class CollapsibleTreeModel<T> {
private model = new Tree<ICollapsibleElement<T>>();
private viewModel: TreeModel<ICollapsibleElement<T>>;
constructor(spliceable: ISpliceable<ICollapsibleTreeListElement<T>>) {
this.viewModel = new TreeModel(spliceable);
}
splice(location: number[], deleteCount: number, toInsert: IIterator<ICollapsibleTreeElement<T>>): IIterator<ICollapsibleTreeElement<T>> {
let length = 0;
toInsert = map(toInsert, el => { length++; return el; });
const result = this.model.splice(location, deleteCount, toInsert);
const [ancestors, elementsToInsert] = this.model.getElementRange(location, length);
const isVisible = ancestors.every(el => !el.collapsed);
if (isVisible) {
this.viewModel.splice(location, deleteCount, elementsToInsert);
}
return result;
}
}
......@@ -14,12 +14,10 @@ export interface IIterator<T> {
next(): IIteratorResult<T>;
}
export function iter<T>(array: T[]): IIterator<T> {
let index = 0;
export function iter<T>(array: T[], index = 0, length = array.length): IIterator<T> {
return {
next(): IIteratorResult<T> {
if (index === array.length) {
if (index >= length) {
return { done: true, value: undefined };
}
......
......@@ -70,6 +70,21 @@ export class Tree<T> {
return nodePath.map(node => node.element);
}
getElementRange(location: number[], length: number): [T[], IIterator<ITreeElement<T>>] {
if (location.length === 0) {
throw new Error('Invalid tree location');
}
const [parentLocation, index] = tail2(location);
const parentPath = this.getNodePath(parentLocation);
const parent = last(parentPath);
return [
parentPath.slice(1).map(node => node.element),
map(iter(parent.children, index, length), asElement)
];
}
getNodes(): ITreeNode<T>[] {
return this.root.children;
}
......
......@@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import * as assert from 'assert';
import { TreeModel, ITreeListElement } from 'vs/base/browser/ui/list/treeModel';
import { TreeModel, ITreeListElement, CollapsibleTreeModel, ICollapsibleTreeListElement } from 'vs/base/browser/ui/list/treeModel';
import { ISpliceable } from 'vs/base/browser/ui/list/splice';
import { iter } from 'vs/base/common/iterator';
......@@ -146,3 +146,63 @@ suite('TreeModel2', () => {
assert.deepEqual(list[1].depth, 1);
});
});
suite('CollapsibleTreeModel', () => {
test('ctor', () => {
const list = [] as ICollapsibleTreeListElement<number>[];
const model = new CollapsibleTreeModel<number>(toSpliceable(list));
assert(model);
assert.equal(list.length, 0);
});
test('insert', () => {
const list = [] as ICollapsibleTreeListElement<number>[];
const model = new CollapsibleTreeModel<number>(toSpliceable(list));
model.splice([0], 0, iter([
{ element: { element: 0, collapsed: false }, children: iter([]) },
{ element: { element: 1, collapsed: false }, children: iter([]) },
{ element: { element: 2, collapsed: false }, children: iter([]) }
]));
assert.deepEqual(list.length, 3);
assert.deepEqual(list[0].element.element, 0);
assert.deepEqual(list[0].depth, 1);
assert.deepEqual(list[1].element.element, 1);
assert.deepEqual(list[1].depth, 1);
assert.deepEqual(list[2].element.element, 2);
assert.deepEqual(list[2].depth, 1);
});
test('deep insert', () => {
const list = [] as ICollapsibleTreeListElement<number>[];
const model = new CollapsibleTreeModel<number>(toSpliceable(list));
model.splice([0], 0, iter([
{
element: { element: 0, collapsed: false }, children: iter([
{ element: { element: 10, collapsed: false }, children: iter([]) },
{ element: { element: 11, collapsed: false }, children: iter([]) },
{ element: { element: 12, collapsed: false }, children: iter([]) },
])
},
{ element: { element: 1, collapsed: false }, children: iter([]) },
{ element: { element: 2, collapsed: false }, children: iter([]) }
]));
assert.deepEqual(list.length, 6);
assert.deepEqual(list[0].element.element, 0);
assert.deepEqual(list[0].depth, 1);
assert.deepEqual(list[1].element.element, 10);
assert.deepEqual(list[1].depth, 2);
assert.deepEqual(list[2].element.element, 11);
assert.deepEqual(list[2].depth, 2);
assert.deepEqual(list[3].element.element, 12);
assert.deepEqual(list[3].depth, 2);
assert.deepEqual(list[4].element.element, 1);
assert.deepEqual(list[4].depth, 1);
assert.deepEqual(list[5].element.element, 2);
assert.deepEqual(list[5].depth, 1);
});
});
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册