diff --git a/src/vs/base/browser/ui/tree/tree.ts b/src/vs/base/browser/ui/tree/tree.ts index 53e5d3acb22..d22c953ee27 100644 --- a/src/vs/base/browser/ui/tree/tree.ts +++ b/src/vs/base/browser/ui/tree/tree.ts @@ -4,18 +4,89 @@ *--------------------------------------------------------------------------------------------*/ import { IDisposable } from 'vs/base/common/lifecycle'; -import { IListOptions, List } from 'vs/base/browser/ui/list/listWidget'; +import { IListOptions, List, IIdentityProvider, IMultipleSelectionController } from 'vs/base/browser/ui/list/listWidget'; import { TreeModel, ITreeListElement, ITreeElement } from 'vs/base/browser/ui/tree/treeModel'; import { IIterator, empty } from 'vs/base/common/iterator'; import { IDelegate, IRenderer } from 'vs/base/browser/ui/list/list'; +import { append, $ } from 'vs/base/browser/dom'; -export interface ITreeOptions extends IListOptions { } +function toTreeListOptions(options?: IListOptions): IListOptions> { + if (!options) { + return undefined; + } -const DefaultOptions: ITreeOptions = { - keyboardSupport: true, - mouseSupport: true, - multipleSelectionSupport: true -}; + let identityProvider: IIdentityProvider> | undefined = undefined; + let multipleSelectionController: IMultipleSelectionController> | undefined = undefined; + + if (options.identityProvider) { + identityProvider = el => options.identityProvider(el.element); + } + + if (options.multipleSelectionController) { + multipleSelectionController = { + isSelectionSingleChangeEvent(e) { + return options.multipleSelectionController.isSelectionSingleChangeEvent({ ...e, element: e.element } as any); + }, + isSelectionRangeChangeEvent(e) { + return options.multipleSelectionController.isSelectionRangeChangeEvent({ ...e, element: e.element } as any); + } + }; + } + + return { + ...options, + identityProvider, + multipleSelectionController + }; +} + +class TreeDelegate implements IDelegate> { + + constructor(private delegate: IDelegate) { } + + getHeight(element: ITreeListElement): number { + return this.delegate.getHeight(element.element); + } + + getTemplateId(element: ITreeListElement): string { + return this.delegate.getTemplateId(element.element); + } +} + +interface ITreeListTemplateData { + twistie: HTMLElement; + templateData: T; +} + +class TreeRenderer implements IRenderer, ITreeListTemplateData> { + + readonly templateId: string; + + constructor(private renderer: IRenderer) { + this.templateId = renderer.templateId; + } + + renderTemplate(container: HTMLElement): ITreeListTemplateData { + const el = append(container, $('.monaco-tree-row')); + const twistie = append(el, $('.row-twistie')); + const contents = append(el, $('.row-contents')); + const templateData = this.renderer.renderTemplate(contents); + + return { twistie, templateData }; + } + + renderElement(element: ITreeListElement, index: number, templateData: ITreeListTemplateData): void { + const { twistie } = templateData; + twistie.innerText = element.collapsed ? '▹' : '◢'; + twistie.style.width = `${element.depth * 20}px`; + + this.renderer.renderElement(element.element, index, templateData.templateData); + } + + disposeTemplate(templateData: ITreeListTemplateData): void { + this.renderer.disposeTemplate(templateData.templateData); + } +} export class Tree implements IDisposable { @@ -26,14 +97,13 @@ export class Tree implements IDisposable { container: HTMLElement, delegate: IDelegate, renderers: IRenderer[], - options: ITreeOptions = DefaultOptions + options?: IListOptions ) { - // TODO map provided args into these - const listDelegate: IDelegate> = undefined; - const listRenderers: IRenderer, any>[] = []; - const listOptions: ITreeOptions> = undefined; + const treeDelegate = new TreeDelegate(delegate); + const treeRenderers = renderers.map(r => new TreeRenderer(r)); + const treeOptions = toTreeListOptions(options); - this.view = new List(container, listDelegate, listRenderers, listOptions); + this.view = new List(container, treeDelegate, treeRenderers, treeOptions); this.model = new TreeModel(this.view); }