Skip to content

Commit

Permalink
Move almost everything out of the tree view constructor (#159553)
Browse files Browse the repository at this point in the history
  • Loading branch information
alexr00 authored Aug 31, 2022
1 parent dffbdeb commit 70c7237
Showing 1 changed file with 81 additions and 28 deletions.
109 changes: 81 additions & 28 deletions src/vs/workbench/browser/parts/views/treeView.ts
Original file line number Diff line number Diff line change
Expand Up @@ -176,22 +176,22 @@ abstract class AbstractTreeView extends Disposable implements ITreeView {
private _hasIconForParentNode = false;
private _hasIconForLeafNode = false;

private readonly collapseAllContextKey: RawContextKey<boolean>;
private readonly collapseAllContext: IContextKey<boolean>;
private readonly collapseAllToggleContextKey: RawContextKey<boolean>;
private readonly collapseAllToggleContext: IContextKey<boolean>;
private readonly refreshContextKey: RawContextKey<boolean>;
private readonly refreshContext: IContextKey<boolean>;
private collapseAllContextKey: RawContextKey<boolean> | undefined;
private collapseAllContext: IContextKey<boolean> | undefined;
private collapseAllToggleContextKey: RawContextKey<boolean> | undefined;
private collapseAllToggleContext: IContextKey<boolean> | undefined;
private refreshContextKey: RawContextKey<boolean> | undefined;
private refreshContext: IContextKey<boolean> | undefined;

private focused: boolean = false;
private domNode!: HTMLElement;
private treeContainer!: HTMLElement;
private treeContainer: HTMLElement | undefined;
private _messageValue: string | undefined;
private _canSelectMany: boolean = false;
private messageElement!: HTMLDivElement;
private messageElement: HTMLElement | undefined;
private tree: Tree | undefined;
private treeLabels: ResourceLabels | undefined;
private treeViewDnd: CustomTreeViewDragAndDrop;
private treeViewDnd: CustomTreeViewDragAndDrop | undefined;
private _container: HTMLElement | undefined;

private root: ITreeItem;
Expand Down Expand Up @@ -242,13 +242,30 @@ abstract class AbstractTreeView extends Disposable implements ITreeView {
) {
super();
this.root = new Root();
this.collapseAllContextKey = new RawContextKey<boolean>(`treeView.${this.id}.enableCollapseAll`, false, localize('treeView.enableCollapseAll', "Whether the the tree view with id {0} enables collapse all.", this.id));
this.collapseAllContext = this.collapseAllContextKey.bindTo(contextKeyService);
this.collapseAllToggleContextKey = new RawContextKey<boolean>(`treeView.${this.id}.toggleCollapseAll`, false, localize('treeView.toggleCollapseAll', "Whether collapse all is toggled for the tree view with id {0}.", this.id));
this.collapseAllToggleContext = this.collapseAllToggleContextKey.bindTo(contextKeyService);
this.refreshContextKey = new RawContextKey<boolean>(`treeView.${this.id}.enableRefresh`, false, localize('treeView.enableRefresh', "Whether the tree view with id {0} enables refresh.", this.id));
this.refreshContext = this.refreshContextKey.bindTo(contextKeyService);
// Try not to add anything that could be costly to this constructor. It gets called once per tree view
// during startup, and anything added here can affect performance.
}

private _isInitialized: boolean = false;
private initialize() {
if (this._isInitialized) {
return;
}
this._isInitialized = true;

// Remember when adding to this method that it isn't called until the the view is visible, meaning that
// properties could be set and events could be fired before we're initialized and that this needs to be handled.

this.contextKeyService.bufferChangeEvents(() => {
this.initializeShowCollapseAllAction();
this.initializeCollapseAllToggle();
this.initializeShowRefreshAction();
});

this.treeViewDnd = this.instantiationService.createInstance(CustomTreeViewDragAndDrop, this.id);
if (this._dragAndDropController) {
this.treeViewDnd.controller = this._dragAndDropController;
}

this._register(this.themeService.onDidFileIconThemeChange(() => this.tree?.rerender()));
this._register(this.themeService.onDidColorThemeChange(() => this.tree?.rerender()));
Expand Down Expand Up @@ -280,7 +297,9 @@ abstract class AbstractTreeView extends Disposable implements ITreeView {
}
set dragAndDropController(dnd: ITreeViewDragAndDropController | undefined) {
this._dragAndDropController = dnd;
this.treeViewDnd.controller = dnd;
if (this.treeViewDnd) {
this.treeViewDnd.controller = dnd;
}
}

private _dataProvider: ITreeViewDataProvider | undefined;
Expand Down Expand Up @@ -418,20 +437,40 @@ abstract class AbstractTreeView extends Disposable implements ITreeView {
return this.isVisible;
}

private initializeShowCollapseAllAction(startingValue: boolean = false) {
if (!this.collapseAllContext) {
this.collapseAllContextKey = new RawContextKey<boolean>(`treeView.${this.id}.enableCollapseAll`, startingValue, localize('treeView.enableCollapseAll', "Whether the the tree view with id {0} enables collapse all.", this.id));
this.collapseAllContext = this.collapseAllContextKey.bindTo(this.contextKeyService);
}
return true;
}

get showCollapseAllAction(): boolean {
return !!this.collapseAllContext.get();
this.initializeShowCollapseAllAction();
return !!this.collapseAllContext?.get();
}

set showCollapseAllAction(showCollapseAllAction: boolean) {
this.collapseAllContext.set(showCollapseAllAction);
this.initializeShowCollapseAllAction(showCollapseAllAction);
this.collapseAllContext?.set(showCollapseAllAction);
}


private initializeShowRefreshAction(startingValue: boolean = false) {
if (!this.refreshContext) {
this.refreshContextKey = new RawContextKey<boolean>(`treeView.${this.id}.enableRefresh`, startingValue, localize('treeView.enableRefresh', "Whether the tree view with id {0} enables refresh.", this.id));
this.refreshContext = this.refreshContextKey.bindTo(this.contextKeyService);
}
}

get showRefreshAction(): boolean {
return !!this.refreshContext.get();
this.initializeShowRefreshAction();
return !!this.refreshContext?.get();
}

set showRefreshAction(showRefreshAction: boolean) {
this.refreshContext.set(showRefreshAction);
this.initializeShowRefreshAction(showRefreshAction);
this.refreshContext?.set(showRefreshAction);
}

private registerActions() {
Expand Down Expand Up @@ -478,6 +517,7 @@ abstract class AbstractTreeView extends Disposable implements ITreeView {
}

setVisibility(isVisible: boolean): void {
this.initialize();
isVisible = !!isVisible;
if (this.isVisible === isVisible) {
return;
Expand Down Expand Up @@ -548,7 +588,7 @@ abstract class AbstractTreeView extends Disposable implements ITreeView {
const renderer = this.instantiationService.createInstance(TreeRenderer, this.id, treeMenus, this.treeLabels, actionViewItemProvider, aligner);
const widgetAriaLabel = this._title;

this.tree = this._register(this.instantiationService.createInstance(Tree, this.id, this.treeContainer, new TreeViewDelegate(), [renderer],
this.tree = this._register(this.instantiationService.createInstance(Tree, this.id, this.treeContainer!, new TreeViewDelegate(), [renderer],
dataSource, {
identityProvider: new TreeViewIdentityProvider(),
accessibilityProvider: {
Expand Down Expand Up @@ -709,9 +749,12 @@ abstract class AbstractTreeView extends Disposable implements ITreeView {
}

private showMessage(message: string): void {
this._messageValue = message;
if (!this.messageElement) {
return;
}
this.messageElement.classList.remove('hide');
this.resetMessageElement();
this._messageValue = message;
if (!isFalsyOrWhitespace(this._message)) {
this.messageElement.textContent = this._messageValue;
}
Expand All @@ -720,18 +763,20 @@ abstract class AbstractTreeView extends Disposable implements ITreeView {

private hideMessage(): void {
this.resetMessageElement();
this.messageElement.classList.add('hide');
this.messageElement?.classList.add('hide');
this.layout(this._height, this._width);
}

private resetMessageElement(): void {
DOM.clearNode(this.messageElement);
if (this.messageElement) {
DOM.clearNode(this.messageElement);
}
}

private _height: number = 0;
private _width: number = 0;
layout(height: number, width: number) {
if (height && width) {
if (height && width && this.messageElement && this.treeContainer) {
this._height = height;
this._width = width;
const treeHeight = height - DOM.getTotalHeight(this.messageElement);
Expand Down Expand Up @@ -831,23 +876,31 @@ abstract class AbstractTreeView extends Disposable implements ITreeView {
}
}

private initializeCollapseAllToggle() {
if (!this.collapseAllToggleContext) {
this.collapseAllToggleContextKey = new RawContextKey<boolean>(`treeView.${this.id}.toggleCollapseAll`, false, localize('treeView.toggleCollapseAll', "Whether collapse all is toggled for the tree view with id {0}.", this.id));
this.collapseAllToggleContext = this.collapseAllToggleContextKey.bindTo(this.contextKeyService);
}
}

private updateCollapseAllToggle() {
if (this.showCollapseAllAction) {
this.collapseAllToggleContext.set(!!this.root.children && (this.root.children.length > 0) &&
this.initializeCollapseAllToggle();
this.collapseAllToggleContext?.set(!!this.root.children && (this.root.children.length > 0) &&
this.root.children.some(value => value.collapsibleState !== TreeItemCollapsibleState.None));
}
}

private updateContentAreas(): void {
const isTreeEmpty = !this.root.children || this.root.children.length === 0;
// Hide tree container only when there is a message and tree is empty and not refreshing
if (this._messageValue && isTreeEmpty && !this.refreshing) {
if (this._messageValue && isTreeEmpty && !this.refreshing && this.treeContainer) {
// If there's a dnd controller then hiding the tree prevents it from being dragged into.
if (!this.dragAndDropController) {
this.treeContainer.classList.add('hide');
}
this.domNode.setAttribute('tabindex', '0');
} else {
} else if (this.treeContainer) {
this.treeContainer.classList.remove('hide');
this.domNode.removeAttribute('tabindex');
}
Expand Down

0 comments on commit 70c7237

Please sign in to comment.