rhamt-vscode-extension
Version:
RHAMT VSCode extension
135 lines (117 loc) • 5.48 kB
text/typescript
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { EventEmitter } from 'vscode';
import { IRhamtNode, IRhamtParentTreeItem, IRhamtTreeItem } from './index';
import { RhamtNode, IRhamtParentNodeInternal } from './RhamtNode';
import { CreatingTreeItem } from './CreatingTreeItem';
import { NotImplementedError } from './errors';
export class RhamtParentNode<T extends IRhamtParentTreeItem = IRhamtParentTreeItem> extends RhamtNode<T> implements IRhamtParentNodeInternal {
private _cachedChildren: RhamtNode[] = [];
private _creatingNodes: RhamtNode[] = [];
private _onNodeCreateEmitter: EventEmitter<IRhamtNode>;
private _clearCache: boolean = true;
private _loadMoreChildrenTask: Promise<void> | undefined;
private _initChildrenTask: Promise<void> | undefined;
public constructor(parent: IRhamtParentNodeInternal | undefined, treeItem: T, onNodeCreateEmitter: EventEmitter<IRhamtNode>) {
super(parent, treeItem);
this._onNodeCreateEmitter = onNodeCreateEmitter;
}
public async getCachedChildren(): Promise<RhamtNode[]> {
if (this._clearCache) {
this._initChildrenTask = this.loadMoreChildren();
}
if (this._initChildrenTask) {
await this._initChildrenTask;
}
return this._cachedChildren;
}
public get creatingNodes(): RhamtNode[] {
return this._creatingNodes;
}
public clearCache(): void {
this._clearCache = true;
}
public async createChild(userOptions?: {}): Promise<RhamtNode> {
if (this.treeItem.createChild) {
let creatingNode: RhamtNode | undefined;
try {
const newTreeItem: IRhamtTreeItem = await this.treeItem.createChild(
this,
(label: string): void => {
creatingNode = new RhamtNode(this, new CreatingTreeItem(label));
this._creatingNodes.push(creatingNode);
//tslint:disable-next-line:no-floating-promises
this.treeDataProvider.refresh(this, false);
},
userOptions);
const newNode: RhamtNode = this.createNewNode(newTreeItem);
await this.addNodeToCache(newNode);
this._onNodeCreateEmitter.fire(newNode);
return newNode;
} finally {
if (creatingNode) {
this._creatingNodes.splice(this._creatingNodes.indexOf(creatingNode), 1);
await this.treeDataProvider.refresh(this, false);
}
}
} else {
throw new NotImplementedError('createChild', this.treeItem);
}
}
public async addNodeToCache(node: RhamtNode): Promise<void> {
let index: number = this._cachedChildren.length;
// tslint:disable-next-line:no-increment-decrement
for (let i: number = 0; i < this._cachedChildren.length; i++) {
if (node.treeItem.label.localeCompare(this._cachedChildren[i].treeItem.label) < 1) {
index = i;
break;
}
}
this._cachedChildren.splice(index, 0, node);
await this.treeDataProvider.refresh(this, false);
}
public async removeNodeFromCache(node: RhamtNode): Promise<void> {
const index: number = this._cachedChildren.indexOf(node);
if (index !== -1) {
this._cachedChildren.splice(index, 1);
await this.treeDataProvider.refresh(this, false);
}
}
public async loadMoreChildren(): Promise<void> {
if (this._loadMoreChildrenTask) {
await this._loadMoreChildrenTask;
} else {
this._loadMoreChildrenTask = this.loadMoreChildrenInternal();
try {
await this._loadMoreChildrenTask;
} finally {
this._loadMoreChildrenTask = undefined;
}
}
}
private async loadMoreChildrenInternal(): Promise<void> {
if (this._clearCache) {
this._cachedChildren = [];
}
const sortCallback: (n1: IRhamtNode, n2: IRhamtNode) => number =
this.treeItem.compareChildren
? this.treeItem.compareChildren
: (n1: RhamtNode, n2: RhamtNode): number => n1.treeItem.label.localeCompare(n2.treeItem.label);
const newTreeItems: IRhamtTreeItem[] = await this.treeItem.loadMoreChildren(this, this._clearCache);
this._cachedChildren = this._cachedChildren
.concat(newTreeItems.map((t: IRhamtTreeItem) => this.createNewNode(t)))
.sort(sortCallback);
this._clearCache = false;
}
private createNewNode(treeItem: IRhamtTreeItem): RhamtNode {
const parentTreeItem: IRhamtParentTreeItem = <IRhamtParentTreeItem>treeItem;
// tslint:disable-next-line:strict-boolean-expressions
if (parentTreeItem.loadMoreChildren) {
return new RhamtParentNode(this, parentTreeItem, this._onNodeCreateEmitter);
} else {
return new RhamtNode(this, treeItem);
}
}
}