mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-16 10:58:30 -05:00
Merge from vscode e1d3dd53d17fb1529a002e4d6fb066db0a0bd385 (#6460)
* Merge from vscode e1d3dd53d17fb1529a002e4d6fb066db0a0bd385 * fix servers icon * fix tests
This commit is contained in:
@@ -102,6 +102,22 @@ class BranchNode implements ISplitView, IDisposable {
|
||||
return Math.min(...this.children.map(c => c.maximumOrthogonalSize));
|
||||
}
|
||||
|
||||
get priority(): LayoutPriority {
|
||||
if (this.children.length === 0) {
|
||||
return LayoutPriority.Normal;
|
||||
}
|
||||
|
||||
const priorities = this.children.map(c => typeof c.priority === 'undefined' ? LayoutPriority.Normal : c.priority);
|
||||
|
||||
if (priorities.some(p => p === LayoutPriority.High)) {
|
||||
return LayoutPriority.High;
|
||||
} else if (priorities.some(p => p === LayoutPriority.Low)) {
|
||||
return LayoutPriority.Low;
|
||||
}
|
||||
|
||||
return LayoutPriority.Normal;
|
||||
}
|
||||
|
||||
get minimumOrthogonalSize(): number {
|
||||
return this.splitview.minimumSize;
|
||||
}
|
||||
|
||||
@@ -325,13 +325,13 @@ export class SplitView extends Disposable {
|
||||
|
||||
container.appendChild(view.element);
|
||||
|
||||
let highPriorityIndex: number | undefined;
|
||||
let highPriorityIndexes: number[] | undefined;
|
||||
|
||||
if (typeof size !== 'number' && size.type === 'split') {
|
||||
highPriorityIndex = size.index;
|
||||
highPriorityIndexes = [size.index];
|
||||
}
|
||||
|
||||
this.relayout(index, highPriorityIndex);
|
||||
this.relayout([index], highPriorityIndexes);
|
||||
this.state = State.Idle;
|
||||
|
||||
if (typeof size !== 'number' && size.type === 'distribute') {
|
||||
@@ -420,17 +420,6 @@ export class SplitView extends Disposable {
|
||||
this.layoutViews();
|
||||
}
|
||||
|
||||
private relayout(lowPriorityIndex?: number, highPriorityIndex?: number): void {
|
||||
const contentSize = this.viewItems.reduce((r, i) => r + i.size, 0);
|
||||
const lowPriorityIndexes = typeof lowPriorityIndex === 'number' ? [lowPriorityIndex] : undefined;
|
||||
const highPriorityIndexes = typeof highPriorityIndex === 'number' ? [highPriorityIndex] : undefined;
|
||||
|
||||
this.resize(this.viewItems.length - 1, this.size - contentSize, undefined, lowPriorityIndexes, highPriorityIndexes);
|
||||
this.distributeEmptySpace();
|
||||
this.layoutViews();
|
||||
this.saveProportions();
|
||||
}
|
||||
|
||||
layout(size: number): void {
|
||||
const previousSize = Math.max(this.size, this.contentSize);
|
||||
this.size = size;
|
||||
@@ -582,7 +571,7 @@ export class SplitView extends Disposable {
|
||||
this.layoutViews();
|
||||
} else {
|
||||
item.size = size;
|
||||
this.relayout(index, undefined);
|
||||
this.relayout([index], undefined);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -597,42 +586,32 @@ export class SplitView extends Disposable {
|
||||
return;
|
||||
}
|
||||
|
||||
const indexes = range(this.viewItems.length).filter(i => i !== index);
|
||||
const lowPriorityIndexes = [...indexes.filter(i => this.viewItems[i].priority === LayoutPriority.Low), index];
|
||||
const highPriorityIndexes = indexes.filter(i => this.viewItems[i].priority === LayoutPriority.High);
|
||||
|
||||
const item = this.viewItems[index];
|
||||
size = Math.round(size);
|
||||
size = clamp(size, item.minimumSize, item.maximumSize);
|
||||
let delta = size - item.size;
|
||||
size = clamp(size, item.minimumSize, Math.min(item.maximumSize, this.size));
|
||||
|
||||
if (delta !== 0 && index < this.viewItems.length - 1) {
|
||||
const downIndexes = range(index + 1, this.viewItems.length);
|
||||
const collapseDown = downIndexes.reduce((r, i) => r + (this.viewItems[i].size - this.viewItems[i].minimumSize), 0);
|
||||
const expandDown = downIndexes.reduce((r, i) => r + (this.viewItems[i].maximumSize - this.viewItems[i].size), 0);
|
||||
const deltaDown = clamp(delta, -expandDown, collapseDown);
|
||||
|
||||
this.resize(index, deltaDown);
|
||||
delta -= deltaDown;
|
||||
}
|
||||
|
||||
if (delta !== 0 && index > 0) {
|
||||
const upIndexes = range(index - 1, -1);
|
||||
const collapseUp = upIndexes.reduce((r, i) => r + (this.viewItems[i].size - this.viewItems[i].minimumSize), 0);
|
||||
const expandUp = upIndexes.reduce((r, i) => r + (this.viewItems[i].maximumSize - this.viewItems[i].size), 0);
|
||||
const deltaUp = clamp(-delta, -collapseUp, expandUp);
|
||||
|
||||
this.resize(index - 1, deltaUp);
|
||||
}
|
||||
|
||||
this.distributeEmptySpace();
|
||||
this.layoutViews();
|
||||
this.saveProportions();
|
||||
item.size = size;
|
||||
this.relayout(lowPriorityIndexes, highPriorityIndexes);
|
||||
this.state = State.Idle;
|
||||
}
|
||||
|
||||
distributeViewSizes(): void {
|
||||
const size = Math.floor(this.size / this.viewItems.length);
|
||||
|
||||
for (let i = 0; i < this.viewItems.length - 1; i++) {
|
||||
this.resizeView(i, size);
|
||||
for (let i = 0; i < this.viewItems.length; i++) {
|
||||
const item = this.viewItems[i];
|
||||
item.size = clamp(size, item.minimumSize, item.maximumSize);
|
||||
}
|
||||
|
||||
const indexes = range(this.viewItems.length);
|
||||
const lowPriorityIndexes = indexes.filter(i => this.viewItems[i].priority === LayoutPriority.Low);
|
||||
const highPriorityIndexes = indexes.filter(i => this.viewItems[i].priority === LayoutPriority.High);
|
||||
|
||||
this.relayout(lowPriorityIndexes, highPriorityIndexes);
|
||||
}
|
||||
|
||||
getViewSize(index: number): number {
|
||||
@@ -643,6 +622,15 @@ export class SplitView extends Disposable {
|
||||
return this.viewItems[index].size;
|
||||
}
|
||||
|
||||
private relayout(lowPriorityIndexes?: number[], highPriorityIndexes?: number[]): void {
|
||||
const contentSize = this.viewItems.reduce((r, i) => r + i.size, 0);
|
||||
|
||||
this.resize(this.viewItems.length - 1, this.size - contentSize, undefined, lowPriorityIndexes, highPriorityIndexes);
|
||||
this.distributeEmptySpace();
|
||||
this.layoutViews();
|
||||
this.saveProportions();
|
||||
}
|
||||
|
||||
private resize(
|
||||
index: number,
|
||||
delta: number,
|
||||
@@ -830,18 +818,26 @@ export class SplitView extends Disposable {
|
||||
private findFirstSnapIndex(indexes: number[]): number | undefined {
|
||||
// visible views first
|
||||
for (const index of indexes) {
|
||||
if (!this.viewItems[index].visible) {
|
||||
const viewItem = this.viewItems[index];
|
||||
|
||||
if (!viewItem.visible) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (this.viewItems[index].snap) {
|
||||
if (viewItem.snap) {
|
||||
return index;
|
||||
}
|
||||
}
|
||||
|
||||
// then, hidden views
|
||||
for (const index of indexes) {
|
||||
if (!this.viewItems[index].visible && this.viewItems[index].snap) {
|
||||
const viewItem = this.viewItems[index];
|
||||
|
||||
if (viewItem.visible && viewItem.maximumSize - viewItem.minimumSize > 0) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
if (!viewItem.visible && viewItem.snap) {
|
||||
return index;
|
||||
}
|
||||
}
|
||||
|
||||
404
src/vs/base/browser/ui/tree/compressedObjectTreeModel.ts
Normal file
404
src/vs/base/browser/ui/tree/compressedObjectTreeModel.ts
Normal file
@@ -0,0 +1,404 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { ISpliceable } from 'vs/base/common/sequence';
|
||||
import { Iterator, ISequence } from 'vs/base/common/iterator';
|
||||
import { Event } from 'vs/base/common/event';
|
||||
import { ITreeModel, ITreeNode, ITreeElement, ICollapseStateChangeEvent, ITreeModelSpliceEvent } from 'vs/base/browser/ui/tree/tree';
|
||||
import { IObjectTreeModelOptions, ObjectTreeModel } from 'vs/base/browser/ui/tree/objectTreeModel';
|
||||
|
||||
export interface ICompressedTreeElement<T> extends ITreeElement<T> {
|
||||
readonly children?: Iterator<ICompressedTreeElement<T>> | ICompressedTreeElement<T>[];
|
||||
readonly incompressible?: boolean;
|
||||
}
|
||||
|
||||
export interface ICompressedTreeNode<T> {
|
||||
readonly elements: T[];
|
||||
readonly incompressible: boolean;
|
||||
}
|
||||
|
||||
export function compress<T>(element: ICompressedTreeElement<T>): ITreeElement<ICompressedTreeNode<T>> {
|
||||
const elements = [element.element];
|
||||
const incompressible = element.incompressible || false;
|
||||
|
||||
let childrenIterator: Iterator<ITreeElement<T>>;
|
||||
let children: ITreeElement<T>[];
|
||||
|
||||
while (true) {
|
||||
childrenIterator = Iterator.from(element.children);
|
||||
children = Iterator.collect(childrenIterator, 2);
|
||||
|
||||
if (children.length !== 1) {
|
||||
break;
|
||||
}
|
||||
|
||||
element = children[0];
|
||||
|
||||
if (element.incompressible) {
|
||||
break;
|
||||
}
|
||||
|
||||
elements.push(element.element);
|
||||
}
|
||||
|
||||
return {
|
||||
element: { elements, incompressible },
|
||||
children: Iterator.map(Iterator.concat(Iterator.fromArray(children), childrenIterator), compress)
|
||||
};
|
||||
}
|
||||
|
||||
export function _decompress<T>(element: ITreeElement<ICompressedTreeNode<T>>, index = 0): ICompressedTreeElement<T> {
|
||||
let children: Iterator<ICompressedTreeElement<T>>;
|
||||
|
||||
if (index < element.element.elements.length - 1) {
|
||||
children = Iterator.single(_decompress(element, index + 1));
|
||||
} else {
|
||||
children = Iterator.map(Iterator.from(element.children), el => _decompress(el, 0));
|
||||
}
|
||||
|
||||
if (index === 0 && element.element.incompressible) {
|
||||
return { element: element.element.elements[index], children, incompressible: true };
|
||||
}
|
||||
|
||||
return { element: element.element.elements[index], children };
|
||||
}
|
||||
|
||||
export function decompress<T>(element: ITreeElement<ICompressedTreeNode<T>>): ICompressedTreeElement<T> {
|
||||
return _decompress(element, 0);
|
||||
}
|
||||
|
||||
export function splice<T>(treeElement: ICompressedTreeElement<T>, element: T, children: Iterator<ICompressedTreeElement<T>>): ICompressedTreeElement<T> {
|
||||
if (treeElement.element === element) {
|
||||
return { element, children };
|
||||
}
|
||||
|
||||
return {
|
||||
...treeElement,
|
||||
children: Iterator.map(Iterator.from(treeElement.children), e => splice(e, element, children))
|
||||
};
|
||||
}
|
||||
|
||||
export interface ICompressedObjectTreeModelOptions<T, TFilterData> extends IObjectTreeModelOptions<ICompressedTreeNode<T>, TFilterData> { }
|
||||
|
||||
export class CompressedObjectTreeModel<T extends NonNullable<any>, TFilterData extends NonNullable<any> = void> implements ITreeModel<ICompressedTreeNode<T> | null, TFilterData, T | null> {
|
||||
|
||||
readonly rootRef = null;
|
||||
|
||||
get onDidSplice(): Event<ITreeModelSpliceEvent<ICompressedTreeNode<T> | null, TFilterData>> { return this.model.onDidSplice; }
|
||||
get onDidChangeCollapseState(): Event<ICollapseStateChangeEvent<ICompressedTreeNode<T>, TFilterData>> { return this.model.onDidChangeCollapseState; }
|
||||
get onDidChangeRenderNodeCount(): Event<ITreeNode<ICompressedTreeNode<T>, TFilterData>> { return this.model.onDidChangeRenderNodeCount; }
|
||||
|
||||
private model: ObjectTreeModel<ICompressedTreeNode<T>, TFilterData>;
|
||||
private nodes = new Map<T | null, ICompressedTreeNode<T>>();
|
||||
|
||||
get size(): number { return this.nodes.size; }
|
||||
|
||||
constructor(list: ISpliceable<ITreeNode<ICompressedTreeNode<T>, TFilterData>>, options: ICompressedObjectTreeModelOptions<T, TFilterData> = {}) {
|
||||
this.model = new ObjectTreeModel(list, options);
|
||||
}
|
||||
|
||||
setChildren(
|
||||
element: T | null,
|
||||
children: ISequence<ICompressedTreeElement<T>> | undefined,
|
||||
onDidCreateNode?: (node: ITreeNode<ICompressedTreeNode<T>, TFilterData>) => void,
|
||||
onDidDeleteNode?: (node: ITreeNode<ICompressedTreeNode<T>, TFilterData>) => void
|
||||
): Iterator<ITreeElement<T | null>> {
|
||||
const insertedElements = new Set<T | null>();
|
||||
const _onDidCreateNode = (node: ITreeNode<ICompressedTreeNode<T>, TFilterData>) => {
|
||||
for (const element of node.element.elements) {
|
||||
insertedElements.add(element);
|
||||
this.nodes.set(element, node.element);
|
||||
}
|
||||
|
||||
// if (this.identityProvider) {
|
||||
// const id = this.identityProvider.getId(node.element).toString();
|
||||
// insertedElementIds.add(id);
|
||||
// this.nodesByIdentity.set(id, node);
|
||||
// }
|
||||
|
||||
if (onDidCreateNode) {
|
||||
onDidCreateNode(node);
|
||||
}
|
||||
};
|
||||
|
||||
const _onDidDeleteNode = (node: ITreeNode<ICompressedTreeNode<T>, TFilterData>) => {
|
||||
for (const element of node.element.elements) {
|
||||
if (!insertedElements.has(element)) {
|
||||
this.nodes.delete(element);
|
||||
}
|
||||
}
|
||||
|
||||
// if (this.identityProvider) {
|
||||
// const id = this.identityProvider.getId(node.element).toString();
|
||||
// if (!insertedElementIds.has(id)) {
|
||||
// this.nodesByIdentity.delete(id);
|
||||
// }
|
||||
// }
|
||||
|
||||
if (onDidDeleteNode) {
|
||||
onDidDeleteNode(node);
|
||||
}
|
||||
};
|
||||
|
||||
if (element === null) {
|
||||
const compressedChildren = Iterator.map(Iterator.from(children), compress);
|
||||
const result = this.model.setChildren(null, compressedChildren, _onDidCreateNode, _onDidDeleteNode);
|
||||
return Iterator.map(result, decompress);
|
||||
}
|
||||
|
||||
const compressedNode = this.nodes.get(element);
|
||||
const node = this.model.getNode(compressedNode) as ITreeNode<ICompressedTreeNode<T>, TFilterData>;
|
||||
const parent = node.parent!;
|
||||
|
||||
const decompressedElement = decompress(node);
|
||||
const splicedElement = splice(decompressedElement, element, Iterator.from(children));
|
||||
const recompressedElement = compress(splicedElement);
|
||||
|
||||
const parentChildren = parent.children
|
||||
.map(child => child === node ? recompressedElement : child);
|
||||
|
||||
this.model.setChildren(parent.element, parentChildren, _onDidCreateNode, _onDidDeleteNode);
|
||||
|
||||
// TODO
|
||||
return Iterator.empty();
|
||||
}
|
||||
|
||||
getListIndex(location: T | null): number {
|
||||
const node = this.getCompressedNode(location);
|
||||
return this.model.getListIndex(node);
|
||||
}
|
||||
|
||||
getListRenderCount(location: T | null): number {
|
||||
const node = this.getCompressedNode(location);
|
||||
return this.model.getListRenderCount(node);
|
||||
}
|
||||
|
||||
getNode(location?: T | null | undefined): ITreeNode<ICompressedTreeNode<T> | null, TFilterData> {
|
||||
if (typeof location === 'undefined') {
|
||||
return this.model.getNode();
|
||||
}
|
||||
|
||||
const node = this.getCompressedNode(location);
|
||||
return this.model.getNode(node);
|
||||
}
|
||||
|
||||
// TODO: review this
|
||||
getNodeLocation(node: ITreeNode<ICompressedTreeNode<T>, TFilterData>): T | null {
|
||||
const compressedNode = this.model.getNodeLocation(node);
|
||||
|
||||
if (compressedNode === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return compressedNode.elements[compressedNode.elements.length - 1];
|
||||
}
|
||||
|
||||
// TODO: review this
|
||||
getParentNodeLocation(location: T | null): T | null {
|
||||
const compressedNode = this.getCompressedNode(location);
|
||||
const parentNode = this.model.getParentNodeLocation(compressedNode);
|
||||
|
||||
if (parentNode === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return parentNode.elements[parentNode.elements.length - 1];
|
||||
}
|
||||
|
||||
getParentElement(location: T | null): ICompressedTreeNode<T> | null {
|
||||
const compressedNode = this.getCompressedNode(location);
|
||||
return this.model.getParentElement(compressedNode);
|
||||
}
|
||||
|
||||
getFirstElementChild(location: T | null): ICompressedTreeNode<T> | null | undefined {
|
||||
const compressedNode = this.getCompressedNode(location);
|
||||
return this.model.getFirstElementChild(compressedNode);
|
||||
}
|
||||
|
||||
getLastElementAncestor(location?: T | null | undefined): ICompressedTreeNode<T> | null | undefined {
|
||||
const compressedNode = typeof location === 'undefined' ? undefined : this.getCompressedNode(location);
|
||||
return this.model.getLastElementAncestor(compressedNode);
|
||||
}
|
||||
|
||||
isCollapsible(location: T | null): boolean {
|
||||
const compressedNode = this.getCompressedNode(location);
|
||||
return this.model.isCollapsible(compressedNode);
|
||||
}
|
||||
|
||||
isCollapsed(location: T | null): boolean {
|
||||
const compressedNode = this.getCompressedNode(location);
|
||||
return this.model.isCollapsed(compressedNode);
|
||||
}
|
||||
|
||||
setCollapsed(location: T | null, collapsed?: boolean | undefined, recursive?: boolean | undefined): boolean {
|
||||
const compressedNode = this.getCompressedNode(location);
|
||||
return this.model.setCollapsed(compressedNode, collapsed, recursive);
|
||||
}
|
||||
|
||||
expandTo(location: T | null): void {
|
||||
const compressedNode = this.getCompressedNode(location);
|
||||
this.model.expandTo(compressedNode);
|
||||
}
|
||||
|
||||
rerender(location: T | null): void {
|
||||
const compressedNode = this.getCompressedNode(location);
|
||||
this.model.rerender(compressedNode);
|
||||
}
|
||||
|
||||
refilter(): void {
|
||||
this.model.refilter();
|
||||
}
|
||||
|
||||
resort(location: T | null = null, recursive = true): void {
|
||||
const compressedNode = this.getCompressedNode(location);
|
||||
this.model.resort(compressedNode, recursive);
|
||||
}
|
||||
|
||||
private getCompressedNode(element: T | null): ICompressedTreeNode<T> | null {
|
||||
if (element === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const node = this.nodes.get(element);
|
||||
|
||||
if (!node) {
|
||||
throw new Error(`Tree element not found: ${element}`);
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
}
|
||||
|
||||
export type ElementMapper<T> = (elements: T[]) => T;
|
||||
export const DefaultElementMapper: ElementMapper<any> = elements => elements[elements.length - 1];
|
||||
|
||||
export type NodeMapper<T, TFilterData> = (node: ITreeNode<ICompressedTreeNode<T> | null, TFilterData>) => ITreeNode<T | null, TFilterData>;
|
||||
|
||||
function mapNode<T, TFilterData>(elementMapper: ElementMapper<T>, node: ITreeNode<ICompressedTreeNode<T> | null, TFilterData>): ITreeNode<T | null, TFilterData> {
|
||||
return {
|
||||
...node,
|
||||
element: node.element === null ? null : elementMapper(node.element.elements),
|
||||
children: node.children.map(child => mapNode(elementMapper, child)),
|
||||
parent: typeof node.parent === 'undefined' ? node.parent : mapNode(elementMapper, node.parent)
|
||||
};
|
||||
}
|
||||
|
||||
function createNodeMapper<T, TFilterData>(elementMapper: ElementMapper<T>): NodeMapper<T, TFilterData> {
|
||||
return node => mapNode(elementMapper, node);
|
||||
}
|
||||
|
||||
export interface ILinearCompressedObjectTreeModelOptions<T, TFilterData> extends ICompressedObjectTreeModelOptions<T, TFilterData> {
|
||||
readonly elementMapper?: ElementMapper<T>;
|
||||
}
|
||||
|
||||
export class LinearCompressedObjectTreeModel<T extends NonNullable<any>, TFilterData extends NonNullable<any> = void> implements ITreeModel<T | null, TFilterData, T | null> {
|
||||
|
||||
readonly rootRef = null;
|
||||
|
||||
get onDidSplice(): Event<ITreeModelSpliceEvent<T | null, TFilterData>> {
|
||||
return Event.map(this.model.onDidSplice, ({ insertedNodes, deletedNodes }) => ({
|
||||
insertedNodes: insertedNodes.map(this.mapNode),
|
||||
deletedNodes: deletedNodes.map(this.mapNode),
|
||||
}));
|
||||
}
|
||||
|
||||
get onDidChangeCollapseState(): Event<ICollapseStateChangeEvent<T | null, TFilterData>> {
|
||||
return Event.map(this.model.onDidChangeCollapseState, ({ node, deep }) => ({
|
||||
node: this.mapNode(node),
|
||||
deep
|
||||
}));
|
||||
}
|
||||
|
||||
get onDidChangeRenderNodeCount(): Event<ITreeNode<T | null, TFilterData>> {
|
||||
return Event.map(this.model.onDidChangeRenderNodeCount, this.mapNode);
|
||||
}
|
||||
|
||||
private mapElement: ElementMapper<T | null>;
|
||||
private mapNode: NodeMapper<T | null, TFilterData>;
|
||||
private model: CompressedObjectTreeModel<T, TFilterData>;
|
||||
|
||||
constructor(
|
||||
list: ISpliceable<ITreeNode<ICompressedTreeNode<T>, TFilterData>>,
|
||||
options: ILinearCompressedObjectTreeModelOptions<T, TFilterData> = {}
|
||||
) {
|
||||
this.mapElement = options.elementMapper || DefaultElementMapper;
|
||||
this.mapNode = createNodeMapper(this.mapElement);
|
||||
this.model = new CompressedObjectTreeModel(list, options);
|
||||
}
|
||||
|
||||
getListIndex(location: T | null): number {
|
||||
return this.model.getListIndex(location);
|
||||
}
|
||||
|
||||
getListRenderCount(location: T | null): number {
|
||||
return this.model.getListRenderCount(location);
|
||||
}
|
||||
|
||||
getNode(location?: T | null | undefined): ITreeNode<T | null, any> {
|
||||
return this.mapNode(this.model.getNode(location));
|
||||
}
|
||||
|
||||
getNodeLocation(node: ITreeNode<T | null, any>): T | null {
|
||||
return node.element;
|
||||
}
|
||||
|
||||
getParentNodeLocation(location: T | null): T | null {
|
||||
return this.model.getParentNodeLocation(location);
|
||||
}
|
||||
|
||||
getParentElement(location: T | null): T | null {
|
||||
const result = this.model.getParentElement(location);
|
||||
|
||||
if (result === null) {
|
||||
return null; // {{SQL CARBON EDIT}} strict-null-check
|
||||
}
|
||||
|
||||
return this.mapElement(result.elements);
|
||||
}
|
||||
|
||||
getFirstElementChild(location: T | null): T | null | undefined {
|
||||
const result = this.model.getFirstElementChild(location);
|
||||
|
||||
if (result === null || typeof result === 'undefined') {
|
||||
return null; // {{SQL CARBON EDIT}} strict-null-check
|
||||
}
|
||||
|
||||
return this.mapElement(result.elements);
|
||||
}
|
||||
|
||||
getLastElementAncestor(location?: T | null | undefined): T | null | undefined {
|
||||
const result = this.model.getLastElementAncestor(location);
|
||||
|
||||
if (result === null || typeof result === 'undefined') {
|
||||
return null; // {{SQL CARBON EDIT}} strict-null-check
|
||||
}
|
||||
|
||||
return this.mapElement(result.elements);
|
||||
}
|
||||
|
||||
isCollapsible(location: T | null): boolean {
|
||||
return this.model.isCollapsible(location);
|
||||
}
|
||||
|
||||
isCollapsed(location: T | null): boolean {
|
||||
return this.model.isCollapsed(location);
|
||||
}
|
||||
|
||||
setCollapsed(location: T | null, collapsed?: boolean | undefined, recursive?: boolean | undefined): boolean {
|
||||
return this.model.setCollapsed(location, collapsed, recursive);
|
||||
}
|
||||
|
||||
expandTo(location: T | null): void {
|
||||
return this.model.expandTo(location);
|
||||
}
|
||||
|
||||
rerender(location: T | null): void {
|
||||
return this.model.rerender(location);
|
||||
}
|
||||
|
||||
refilter(): void {
|
||||
return this.model.refilter();
|
||||
}
|
||||
}
|
||||
@@ -53,7 +53,7 @@ export class ObjectTreeModel<T extends NonNullable<any>, TFilterData extends Non
|
||||
children: ISequence<ITreeElement<T>> | undefined,
|
||||
onDidCreateNode?: (node: ITreeNode<T, TFilterData>) => void,
|
||||
onDidDeleteNode?: (node: ITreeNode<T, TFilterData>) => void
|
||||
): Iterator<ITreeElement<T | null>> {
|
||||
): Iterator<ITreeElement<T>> {
|
||||
const location = this.getElementLocation(element);
|
||||
return this._setChildren(location, this.preserveCollapseState(children), onDidCreateNode, onDidDeleteNode);
|
||||
}
|
||||
@@ -63,7 +63,7 @@ export class ObjectTreeModel<T extends NonNullable<any>, TFilterData extends Non
|
||||
children: ISequence<ITreeElement<T>> | undefined,
|
||||
onDidCreateNode?: (node: ITreeNode<T, TFilterData>) => void,
|
||||
onDidDeleteNode?: (node: ITreeNode<T, TFilterData>) => void
|
||||
): Iterator<ITreeElement<T | null>> {
|
||||
): Iterator<ITreeElement<T>> {
|
||||
const insertedElements = new Set<T | null>();
|
||||
const insertedElementIds = new Set<string>();
|
||||
|
||||
@@ -107,7 +107,7 @@ export class ObjectTreeModel<T extends NonNullable<any>, TFilterData extends Non
|
||||
_onDidDeleteNode
|
||||
);
|
||||
|
||||
return result;
|
||||
return result as Iterator<ITreeElement<T>>;
|
||||
}
|
||||
|
||||
private preserveCollapseState(elements: ISequence<ITreeElement<T>> | undefined): ISequence<ITreeElement<T>> {
|
||||
@@ -144,7 +144,7 @@ export class ObjectTreeModel<T extends NonNullable<any>, TFilterData extends Non
|
||||
});
|
||||
}
|
||||
|
||||
rerender(element: T): void {
|
||||
rerender(element: T | null): void {
|
||||
const location = this.getElementLocation(element);
|
||||
this.model.rerender(location);
|
||||
}
|
||||
@@ -190,32 +190,32 @@ export class ObjectTreeModel<T extends NonNullable<any>, TFilterData extends Non
|
||||
return this.model.getLastElementAncestor(location);
|
||||
}
|
||||
|
||||
getListIndex(element: T): number {
|
||||
getListIndex(element: T | null): number {
|
||||
const location = this.getElementLocation(element);
|
||||
return this.model.getListIndex(location);
|
||||
}
|
||||
|
||||
getListRenderCount(element: T): number {
|
||||
getListRenderCount(element: T | null): number {
|
||||
const location = this.getElementLocation(element);
|
||||
return this.model.getListRenderCount(location);
|
||||
}
|
||||
|
||||
isCollapsible(element: T): boolean {
|
||||
isCollapsible(element: T | null): boolean {
|
||||
const location = this.getElementLocation(element);
|
||||
return this.model.isCollapsible(location);
|
||||
}
|
||||
|
||||
isCollapsed(element: T): boolean {
|
||||
isCollapsed(element: T | null): boolean {
|
||||
const location = this.getElementLocation(element);
|
||||
return this.model.isCollapsed(location);
|
||||
}
|
||||
|
||||
setCollapsed(element: T, collapsed?: boolean, recursive?: boolean): boolean {
|
||||
setCollapsed(element: T | null, collapsed?: boolean, recursive?: boolean): boolean {
|
||||
const location = this.getElementLocation(element);
|
||||
return this.model.setCollapsed(location, collapsed, recursive);
|
||||
}
|
||||
|
||||
expandTo(element: T): void {
|
||||
expandTo(element: T | null): void {
|
||||
const location = this.getElementLocation(element);
|
||||
this.model.expandTo(location);
|
||||
}
|
||||
@@ -238,11 +238,15 @@ export class ObjectTreeModel<T extends NonNullable<any>, TFilterData extends Non
|
||||
return node;
|
||||
}
|
||||
|
||||
getNodeLocation(node: ITreeNode<T, TFilterData>): T {
|
||||
getNodeLocation(node: ITreeNode<T, TFilterData>): T | null {
|
||||
return node.element;
|
||||
}
|
||||
|
||||
getParentNodeLocation(element: T): T | null {
|
||||
getParentNodeLocation(element: T | null): T | null {
|
||||
if (element === null) {
|
||||
throw new Error(`Invalid getParentNodeLocation call`);
|
||||
}
|
||||
|
||||
const node = this.nodes.get(element);
|
||||
|
||||
if (!node) {
|
||||
|
||||
@@ -124,6 +124,7 @@ export interface ITreeModel<T, TFilterData, TRef> {
|
||||
setCollapsed(location: TRef, collapsed?: boolean, recursive?: boolean): boolean;
|
||||
expandTo(location: TRef): void;
|
||||
|
||||
rerender(location: TRef): void;
|
||||
refilter(): void;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user