From c0b509ed0b3274a312a995db292e5fb6eeb46dbe Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Tue, 22 Aug 2017 19:06:15 +0200 Subject: [PATCH] Fix #32631 Make tree view data providers disposable On main tree views disposed - Deregister and dispose data providers --- .../electron-browser/mainThreadTreeViews.ts | 23 +++++++++++++------ .../workbench/parts/views/browser/treeView.ts | 17 ++++++++------ .../parts/views/browser/viewsRegistry.ts | 6 +++++ src/vs/workbench/parts/views/common/views.ts | 2 ++ 4 files changed, 34 insertions(+), 14 deletions(-) diff --git a/src/vs/workbench/api/electron-browser/mainThreadTreeViews.ts b/src/vs/workbench/api/electron-browser/mainThreadTreeViews.ts index bedbc0d6dd5..75c077967d2 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadTreeViews.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadTreeViews.ts @@ -6,6 +6,7 @@ import Event, { Emitter } from 'vs/base/common/event'; import { TPromise } from 'vs/base/common/winjs.base'; +import { Disposable } from 'vs/base/common/lifecycle'; import { ExtHostContext, MainThreadTreeViewsShape, ExtHostTreeViewsShape, MainContext, IExtHostContext } from '../node/extHost.protocol'; import { IMessageService, Severity } from 'vs/platform/message/common/message'; import { ViewsRegistry } from 'vs/workbench/parts/views/browser/viewsRegistry'; @@ -13,7 +14,7 @@ import { ITreeViewDataProvider, ITreeItem, TreeItemCollapsibleState } from 'vs/w import { extHostNamedCustomer } from 'vs/workbench/api/electron-browser/extHostCustomers'; @extHostNamedCustomer(MainContext.MainThreadTreeViews) -export class MainThreadTreeViews implements MainThreadTreeViewsShape { +export class MainThreadTreeViews extends Disposable implements MainThreadTreeViewsShape { private _proxy: ExtHostTreeViewsShape; @@ -21,16 +22,12 @@ export class MainThreadTreeViews implements MainThreadTreeViewsShape { extHostContext: IExtHostContext, @IMessageService private messageService: IMessageService ) { + super(); this._proxy = extHostContext.get(ExtHostContext.ExtHostTreeViews); } - public dispose(): void { - // TODO@Sandeep: please implement this - // will be called when the extension host process is gone. - } - $registerView(treeViewId: string): void { - ViewsRegistry.registerTreeViewDataProvider(treeViewId, new TreeViewDataProvider(treeViewId, this._proxy, this.messageService)); + ViewsRegistry.registerTreeViewDataProvider(treeViewId, this._register(new TreeViewDataProvider(treeViewId, this._proxy, this.messageService))); } $refresh(treeViewId: string, treeItemHandles: number[]): void { @@ -39,6 +36,11 @@ export class MainThreadTreeViews implements MainThreadTreeViewsShape { treeViewDataProvider.refresh(treeItemHandles); } } + + dispose(): void { + ViewsRegistry.deregisterTreeViewDataProviders(); + super.dispose(); + } } type TreeItemHandle = number; @@ -48,6 +50,9 @@ class TreeViewDataProvider implements ITreeViewDataProvider { private _onDidChange: Emitter = new Emitter(); readonly onDidChange: Event = this._onDidChange.event; + private _onDispose: Emitter = new Emitter(); + readonly onDispose: Event = this._onDispose.event; + private childrenMap: Map = new Map(); private itemsMap: Map = new Map(); @@ -94,6 +99,10 @@ class TreeViewDataProvider implements ITreeViewDataProvider { } } + dispose(): void { + this._onDispose.fire(); + } + private clearChildren(treeItemHandle: TreeItemHandle): void { const children = this.childrenMap.get(treeItemHandle); if (children) { diff --git a/src/vs/workbench/parts/views/browser/treeView.ts b/src/vs/workbench/parts/views/browser/treeView.ts index 6c5e97f607d..e62b7e52b37 100644 --- a/src/vs/workbench/parts/views/browser/treeView.ts +++ b/src/vs/workbench/parts/views/browser/treeView.ts @@ -40,7 +40,6 @@ export class TreeView extends CollapsibleView { private activated: boolean = false; private treeInputPromise: TPromise; - private dataProviderRegisteredListener: IDisposable; private dataProviderElementChangeListener: IDisposable; private disposables: IDisposable[] = []; @@ -138,14 +137,13 @@ export class TreeView extends CollapsibleView { this.treeInputPromise = this.tree.setInput(new Root()); } else { this.treeInputPromise = new TPromise((c, e) => { - this.dataProviderRegisteredListener = ViewsRegistry.onTreeViewDataProviderRegistered(id => { + this.disposables.push(ViewsRegistry.onTreeViewDataProviderRegistered(id => { if (this.id === id) { if (this.listenToDataProvider()) { this.tree.setInput(new Root()).then(() => c(null)); - this.dataProviderRegisteredListener.dispose(); } } - }); + })); }); } } @@ -161,6 +159,11 @@ export class TreeView extends CollapsibleView { this.dataProviderElementChangeListener.dispose(); } this.dataProviderElementChangeListener = dataProvider.onDidChange(element => this.refresh(element)); + const disposable = dataProvider.onDispose(() => { + this.dataProviderElementChangeListener.dispose(); + this.tree.setInput(new Root()); + disposable.dispose(); + }); return true; } return false; @@ -191,9 +194,6 @@ export class TreeView extends CollapsibleView { } dispose(): void { - if (this.dataProviderRegisteredListener) { - this.dataProviderRegisteredListener.dispose(); - } dispose(this.disposables); if (this.dataProviderElementChangeListener) { this.dataProviderElementChangeListener.dispose(); @@ -222,6 +222,9 @@ class TreeDataSource implements IDataSource { } public hasChildren(tree: ITree, node: ITreeItem): boolean { + if (!this.getDataProvider()) { + return false; + } return node.collapsibleState === TreeItemCollapsibleState.Collapsed || node.collapsibleState === TreeItemCollapsibleState.Expanded; } diff --git a/src/vs/workbench/parts/views/browser/viewsRegistry.ts b/src/vs/workbench/parts/views/browser/viewsRegistry.ts index e6badc6ed3e..2415d22c40c 100644 --- a/src/vs/workbench/parts/views/browser/viewsRegistry.ts +++ b/src/vs/workbench/parts/views/browser/viewsRegistry.ts @@ -63,6 +63,8 @@ export interface IViewsRegistry { registerTreeViewDataProvider(id: string, factory: ITreeViewDataProvider): void; + deregisterTreeViewDataProviders(): void; + getViews(loc: ViewLocation): IViewDescriptor[]; getTreeViewDataProvider(id: string): ITreeViewDataProvider; @@ -113,6 +115,10 @@ export const ViewsRegistry: IViewsRegistry = new class { this._onTreeViewDataProviderRegistered.fire(id); } + deregisterTreeViewDataProviders(): void { + this._treeViewDataPoviders.clear(); + } + getViews(loc: ViewLocation): IViewDescriptor[] { return this._views.get(loc) || []; } diff --git a/src/vs/workbench/parts/views/common/views.ts b/src/vs/workbench/parts/views/common/views.ts index ce1116e1378..730931ed339 100644 --- a/src/vs/workbench/parts/views/common/views.ts +++ b/src/vs/workbench/parts/views/common/views.ts @@ -41,6 +41,8 @@ export interface ITreeViewDataProvider { onDidChange: Event; + onDispose: Event; + getElements(): TPromise; getChildren(element: ITreeItem): TPromise; -- GitLab