diff --git a/src/sql/base/browser/ui/propertiesContainer/propertiesContainer.component.ts b/src/sql/base/browser/ui/propertiesContainer/propertiesContainer.component.ts index 336fcddffe..b05c8bcee9 100644 --- a/src/sql/base/browser/ui/propertiesContainer/propertiesContainer.component.ts +++ b/src/sql/base/browser/ui/propertiesContainer/propertiesContainer.component.ts @@ -45,12 +45,12 @@ export class PropertiesContainer extends Disposable implements OnInit, OnDestroy } ngAfterViewInit(): void { - this._togglePropertiesAction.onDidChange((e) => { + this._register(this._togglePropertiesAction.onDidChange((e) => { if (e.expanded !== undefined) { this._changeRef.detectChanges(); } - }); - this._actionbar = new ActionBar(this._actionbarRef.nativeElement); + })); + this._actionbar = this._register(new ActionBar(this._actionbarRef.nativeElement)); this._actionbar.push(this._togglePropertiesAction, { icon: true, label: false }); } diff --git a/src/sql/base/browser/ui/table/asyncDataView.ts b/src/sql/base/browser/ui/table/asyncDataView.ts index c8238e9783..6cbfa87b4c 100644 --- a/src/sql/base/browser/ui/table/asyncDataView.ts +++ b/src/sql/base/browser/ui/table/asyncDataView.ts @@ -6,6 +6,7 @@ import { IDisposableDataProvider } from 'sql/base/common/dataProvider'; import { CancellationTokenSource } from 'vs/base/common/cancellation'; import { Emitter, Event } from 'vs/base/common/event'; +import { Disposable } from 'vs/base/common/lifecycle'; export interface IObservableCollection { getLength(): number; @@ -79,7 +80,7 @@ class DataWindow { } } -export class VirtualizedCollection implements IObservableCollection { +export class VirtualizedCollection extends Disposable implements IObservableCollection { private _bufferWindowBefore: DataWindow; private _window: DataWindow; private _bufferWindowAfter: DataWindow; @@ -93,21 +94,16 @@ export class VirtualizedCollection implements IObserv private length: number, loadFn: (offset: number, count: number) => Thenable ) { + super(); let loadCompleteCallback = (start: number, end: number) => { if (this.collectionChangedCallback) { this.collectionChangedCallback(start, end - start); } }; - this._bufferWindowBefore = new DataWindow(loadFn, placeHolderGenerator, loadCompleteCallback); - this._window = new DataWindow(loadFn, placeHolderGenerator, loadCompleteCallback); - this._bufferWindowAfter = new DataWindow(loadFn, placeHolderGenerator, loadCompleteCallback); - } - - dispose() { - this._bufferWindowAfter.dispose(); - this._bufferWindowBefore.dispose(); - this._window.dispose(); + this._bufferWindowBefore = this._register(new DataWindow(loadFn, placeHolderGenerator, loadCompleteCallback)); + this._window = this._register(new DataWindow(loadFn, placeHolderGenerator, loadCompleteCallback)); + this._bufferWindowAfter = this._register(new DataWindow(loadFn, placeHolderGenerator, loadCompleteCallback)); } public setCollectionChangedCallback(callback: (startIndex: number, count: number) => void): void { @@ -200,15 +196,18 @@ export class VirtualizedCollection implements IObserv } } -export class AsyncDataProvider implements IDisposableDataProvider { +export class AsyncDataProvider extends Disposable implements IDisposableDataProvider { - private _onFilterStateChange = new Emitter(); + private _onFilterStateChange = this._register(new Emitter()); get onFilterStateChange(): Event { return this._onFilterStateChange.event; } - private _onSortComplete = new Emitter>(); + private _onSortComplete = this._register(new Emitter>()); get onSortComplete(): Event> { return this._onSortComplete.event; } - constructor(public dataRows: IObservableCollection) { } + constructor(public dataRows: IObservableCollection) { + super(); + this._register(dataRows); + } public get isDataInMemory(): boolean { return false; @@ -250,10 +249,6 @@ export class AsyncDataProvider implements IDisposable return this.dataRows.getLength(); } - dispose() { - this.dataRows.dispose(); - } - getItems(): T[] { throw new Error('Method not supported.'); } diff --git a/src/sql/base/browser/ui/table/hybridDataProvider.ts b/src/sql/base/browser/ui/table/hybridDataProvider.ts index ed88b2987a..796114dbe9 100644 --- a/src/sql/base/browser/ui/table/hybridDataProvider.ts +++ b/src/sql/base/browser/ui/table/hybridDataProvider.ts @@ -8,7 +8,7 @@ import { FilterableColumn } from 'sql/base/browser/ui/table/interfaces'; import { CellValueGetter, TableDataView, TableFilterFunc, TableSortFunc } from 'sql/base/browser/ui/table/tableDataView'; import { IDisposableDataProvider } from 'sql/base/common/dataProvider'; import { Event, Emitter } from 'vs/base/common/event'; -import { DisposableStore } from 'vs/base/common/lifecycle'; +import { Disposable } from 'vs/base/common/lifecycle'; export interface HybridDataProviderOptions { inMemoryDataProcessing: boolean; @@ -19,16 +19,15 @@ export interface HybridDataProviderOptions { * Used to abstract the underlying data provider, based on the options, if we are allowing in-memory data processing and the threshold is not reached the * a TableDataView will be used to provide in memory data source, otherwise it will be using the async data provider. */ -export class HybridDataProvider implements IDisposableDataProvider { +export class HybridDataProvider extends Disposable implements IDisposableDataProvider { private _asyncDataProvider: AsyncDataProvider; private _tableDataProvider: TableDataView; private _dataCached: boolean = false; - private _disposableStore = new DisposableStore(); - private _onFilterStateChange = new Emitter(); + private _onFilterStateChange = this._register(new Emitter()); get onFilterStateChange(): Event { return this._onFilterStateChange.event; } - private _onSortComplete = new Emitter>(); + private _onSortComplete = this._register(new Emitter>()); get onSortComplete(): Event> { return this._onSortComplete.event; } constructor(dataRows: IObservableCollection, @@ -37,22 +36,23 @@ export class HybridDataProvider implements IDisposabl sortFn: TableSortFunc, valueGetter: CellValueGetter, private readonly _options: HybridDataProviderOptions) { + super(); this._asyncDataProvider = new AsyncDataProvider(dataRows); this._tableDataProvider = new TableDataView(undefined, undefined, sortFn, filterFn, valueGetter); - this._disposableStore.add(this._asyncDataProvider.onFilterStateChange(() => { + this._register(this._asyncDataProvider.onFilterStateChange(() => { this._onFilterStateChange.fire(); })); - this._disposableStore.add(this._asyncDataProvider.onSortComplete((args) => { + this._register(this._asyncDataProvider.onSortComplete((args) => { this._onSortComplete.fire(args); })); - this._disposableStore.add(this._tableDataProvider.onFilterStateChange(() => { + this._register(this._tableDataProvider.onFilterStateChange(() => { this._onFilterStateChange.fire(); })); - this._disposableStore.add(this._tableDataProvider.onSortComplete((args) => { + this._register(this._tableDataProvider.onSortComplete((args) => { this._onSortComplete.fire(args); })); - this._disposableStore.add(this._asyncDataProvider); - this._disposableStore.add(this._tableDataProvider); + this._register(this._asyncDataProvider); + this._register(this._tableDataProvider); } public get isDataInMemory(): boolean { @@ -76,10 +76,6 @@ export class HybridDataProvider implements IDisposabl this._asyncDataProvider.dataRows = value; } - public dispose(): void { - this._disposableStore.dispose(); - } - public getLength(): number { return this.provider.getLength(); } diff --git a/src/sql/base/browser/ui/table/plugins/checkboxColumn.plugin.ts b/src/sql/base/browser/ui/table/plugins/checkboxColumn.plugin.ts index 1472a3b72c..8875898587 100644 --- a/src/sql/base/browser/ui/table/plugins/checkboxColumn.plugin.ts +++ b/src/sql/base/browser/ui/table/plugins/checkboxColumn.plugin.ts @@ -10,6 +10,7 @@ import { Emitter } from 'vs/base/common/event'; import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent'; import { KeyCode } from 'vs/base/common/keyCodes'; import { convertJQueryKeyDownEvent } from 'sql/base/browser/dom'; +import { Disposable } from 'vs/base/common/lifecycle'; export interface CheckBoxCellValue { enabled?: boolean; @@ -26,14 +27,14 @@ export interface CheckBoxChangedEventArgs { export interface CheckBoxColumnOptions extends BaseTableColumnOptions { } -export class CheckBoxColumn implements Slick.Plugin, TableColumn { +export class CheckBoxColumn extends Disposable implements Slick.Plugin, TableColumn { private _handler = new Slick.EventHandler(); private _grid!: Slick.Grid; - private _onChange = new Emitter>(); + private _onChange = this._register(new Emitter>()); public onChange = this._onChange.event; constructor(private options: CheckBoxColumnOptions) { - + super(); } public init(grid: Slick.Grid): void { diff --git a/src/sql/base/browser/ui/table/plugins/checkboxSelectColumn.plugin.ts b/src/sql/base/browser/ui/table/plugins/checkboxSelectColumn.plugin.ts index c9790b759e..77c6642df1 100644 --- a/src/sql/base/browser/ui/table/plugins/checkboxSelectColumn.plugin.ts +++ b/src/sql/base/browser/ui/table/plugins/checkboxSelectColumn.plugin.ts @@ -10,6 +10,7 @@ import { escape } from 'sql/base/common/strings'; import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent'; import { Emitter, Event as vsEvent } from 'vs/base/common/event'; import { KeyCode } from 'vs/base/common/keyCodes'; +import { Disposable } from 'vs/base/common/lifecycle'; import 'vs/css!./media/checkboxSelectColumn.plugin'; import * as nls from 'vs/nls'; @@ -56,19 +57,19 @@ const defaultOptions: ICheckboxSelectColumnOptions = { width: 30 }; -export class CheckboxSelectColumn implements Slick.Plugin { - +export class CheckboxSelectColumn extends Disposable implements Slick.Plugin { private _grid!: Slick.Grid; private _handler = new Slick.EventHandler(); private _options: ICheckboxSelectColumnOptions; public index: number; private _headerCheckbox: HTMLInputElement | undefined; - private _onChange = new Emitter(); - private _onCheckAllChange = new Emitter(); + private _onChange = this._register(new Emitter()); + private _onCheckAllChange = this._register(new Emitter()); public readonly onChange: vsEvent = this._onChange.event; public readonly onCheckAllChange: vsEvent = this._onCheckAllChange.event; constructor(options?: ICheckboxSelectColumnOptions, columnIndex?: number) { + super(); this._options = mixin(options, defaultOptions, false); this._options.headerCssClass = options.headerCssClass ? options.headerCssClass + ' ' + defaultOptions.headerCssClass : defaultOptions.headerCssClass; this._options.cssClass = options.cssClass ? options.cssClass + ' ' + defaultOptions.cssClass : defaultOptions.cssClass; diff --git a/src/sql/base/browser/ui/table/plugins/copyKeybind.plugin.ts b/src/sql/base/browser/ui/table/plugins/copyKeybind.plugin.ts index 21b1399223..c23c9e1cfc 100644 --- a/src/sql/base/browser/ui/table/plugins/copyKeybind.plugin.ts +++ b/src/sql/base/browser/ui/table/plugins/copyKeybind.plugin.ts @@ -8,15 +8,15 @@ import { KeyCode, KeyMod } from 'vs/base/common/keyCodes'; import { Emitter, Event } from 'vs/base/common/event'; import { isUndefinedOrNull } from 'vs/base/common/types'; import { convertJQueryKeyDownEvent } from 'sql/base/browser/dom'; +import { Disposable } from 'vs/base/common/lifecycle'; /** * Implements the various additional navigation keybindings we want out of slickgrid */ -export class CopyKeybind implements Slick.Plugin { +export class CopyKeybind extends Disposable implements Slick.Plugin { private grid!: Slick.Grid; private handler = new Slick.EventHandler(); - - private _onCopy = new Emitter(); + private _onCopy = this._register(new Emitter()); public onCopy: Event = this._onCopy.event; public init(grid: Slick.Grid) { @@ -56,5 +56,4 @@ export class CopyKeybind implements Slick.Plugin { e.browserEvent.stopImmediatePropagation } } - } diff --git a/src/sql/base/browser/ui/table/plugins/headerFilter.plugin.ts b/src/sql/base/browser/ui/table/plugins/headerFilter.plugin.ts index e6127662b6..10e14da5da 100644 --- a/src/sql/base/browser/ui/table/plugins/headerFilter.plugin.ts +++ b/src/sql/base/browser/ui/table/plugins/headerFilter.plugin.ts @@ -7,7 +7,7 @@ import { localize } from 'vs/nls'; import { Button } from 'sql/base/browser/ui/button/button'; import { FilterableColumn } from 'sql/base/browser/ui/table/interfaces'; import { addDisposableListener, EventType, EventHelper, $, isAncestor, clearNode, append } from 'vs/base/browser/dom'; -import { DisposableStore, dispose, IDisposable } from 'vs/base/common/lifecycle'; +import { Disposable, DisposableStore, dispose, IDisposable } from 'vs/base/common/lifecycle'; import { withNullAsUndefined } from 'vs/base/common/types'; import { IDisposableDataProvider, instanceOfIDisposableDataProvider } from 'sql/base/common/dataProvider'; import { IContextViewProvider } from 'vs/base/browser/ui/contextview/contextview'; @@ -53,7 +53,7 @@ const ShowFilterText: string = localize('headerFilter.showFilter', "Show Filter" export const FilterButtonWidth: number = 34; -export class HeaderFilter { +export class HeaderFilter extends Disposable { public onFilterApplied = new Slick.Event<{ grid: Slick.Grid, column: FilterableColumn }>(); public onCommand = new Slick.Event>(); @@ -81,6 +81,7 @@ export class HeaderFilter { private listContainer?: HTMLElement; constructor(private readonly options: ITableFilterOptions, private readonly contextViewProvider: IContextViewProvider, private readonly notificationProvider?: NotificationProvider) { + super(); } public init(grid: Slick.Grid): void { @@ -198,10 +199,10 @@ export class HeaderFilter { }); - this.searchInputBox = new InputBox(append(searchRow, $('.search-input')), this.contextViewProvider, { + this.searchInputBox = this._register(new InputBox(append(searchRow, $('.search-input')), this.contextViewProvider, { placeholder: localize('table.searchPlaceHolder', "Search"), inputBoxStyles: this.options - }); + })); const visibleCountContainer = append(searchRow, $('.visible-count')); visibleCountContainer.setAttribute('aria-live', 'polite'); visibleCountContainer.setAttribute('aria-atomic', 'true'); @@ -215,11 +216,11 @@ export class HeaderFilter { countFormat: localize({ key: 'tableFilter.selectedCount', comment: ['This tells the user how many items are selected in the list'] }, "{0} Selected") }, this.options); - this.searchInputBox.onDidChange(async (newString) => { + this._register(this.searchInputBox.onDidChange(async (newString) => { this.filteredListData = this.listData.filter(element => element.value?.toUpperCase().indexOf(newString.toUpperCase()) !== -1); this.list.splice(0, this.list.length, this.filteredListData); this.updateSelectionState(); - }); + })); } private async createFilterList(): Promise { @@ -262,7 +263,9 @@ export class HeaderFilter { // work item to remove the 'Error:' string check: https://github.com/microsoft/azuredatastudio/issues/15206 const filterItem = filterItems[i]; if (!filterItem || filterItem.indexOf('Error:') < 0) { - this.listData.push(new TableFilterListElement(filterItem, filtered)); + let element = new TableFilterListElement(filterItem, filtered); + this._register(element); + this.listData.push(); } } @@ -518,11 +521,12 @@ export class HeaderFilter { } } -class TableFilterListElement { - private readonly _onCheckStateChanged = new Emitter(); +class TableFilterListElement extends Disposable { + private readonly _onCheckStateChanged = this._register(new Emitter()); private _checked: boolean; constructor(val: string, checked: boolean) { + super(); this.value = val; this._checked = checked; diff --git a/src/sql/base/browser/ui/table/plugins/tableColumn.ts b/src/sql/base/browser/ui/table/plugins/tableColumn.ts index 63acd931b6..80d8a73dc9 100644 --- a/src/sql/base/browser/ui/table/plugins/tableColumn.ts +++ b/src/sql/base/browser/ui/table/plugins/tableColumn.ts @@ -6,6 +6,7 @@ import { convertJQueryKeyDownEvent } from 'sql/base/browser/dom'; import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent'; import { Emitter } from 'vs/base/common/event'; import { KeyCode } from 'vs/base/common/keyCodes'; +import { Disposable } from 'vs/base/common/lifecycle'; export interface TableColumn { readonly definition: Slick.Column; @@ -25,13 +26,14 @@ export interface ClickableColumnOptions { enabledField?: string; } -export abstract class BaseClickableColumn implements Slick.Plugin, TableColumn { +export abstract class BaseClickableColumn extends Disposable implements Slick.Plugin, TableColumn { protected _handler = new Slick.EventHandler(); protected _grid!: Slick.Grid; - private _onClick = new Emitter>(); + private _onClick = this._register(new Emitter>()); public onClick = this._onClick.event; constructor(private readonly _options: ClickableColumnOptions) { + super(); } public init(grid: Slick.Grid): void { @@ -45,6 +47,9 @@ export abstract class BaseClickableColumn implements this._handler.unsubscribeAll(); } + public override dispose(): void { + this.destroy(); + } /** * Returns the column definition. * Note when implementing this abstract getter: diff --git a/src/sql/base/browser/ui/table/tableDataView.ts b/src/sql/base/browser/ui/table/tableDataView.ts index b958554ff9..72a82ca25d 100644 --- a/src/sql/base/browser/ui/table/tableDataView.ts +++ b/src/sql/base/browser/ui/table/tableDataView.ts @@ -9,6 +9,7 @@ import { compare as stringCompare } from 'vs/base/common/strings'; import { FilterableColumn } from 'sql/base/browser/ui/table/interfaces'; import { IDisposableDataProvider } from 'sql/base/common/dataProvider'; +import { Disposable } from 'vs/base/common/lifecycle'; export interface IFindPosition { col: number; @@ -66,7 +67,7 @@ export function defaultFilter(data: T[], columns: Fil return filteredData; } -export class TableDataView implements IDisposableDataProvider { +export class TableDataView extends Disposable implements IDisposableDataProvider { //The data exposed publicly, when filter is enabled, _data holds the filtered data. private _data: Array; //Used when filtering is enabled, _allData holds the complete set of data. @@ -76,16 +77,16 @@ export class TableDataView implements IDisposableData private _filterEnabled: boolean; private _currentColumnFilters: FilterableColumn[]; - private _onRowCountChange = new Emitter(); + private _onRowCountChange = this._register(new Emitter()); get onRowCountChange(): Event { return this._onRowCountChange.event; } - private _onFindCountChange = new Emitter(); + private _onFindCountChange = this._register(new Emitter()); get onFindCountChange(): Event { return this._onFindCountChange.event; } - private _onFilterStateChange = new Emitter(); + private _onFilterStateChange = this._register(new Emitter()); get onFilterStateChange(): Event { return this._onFilterStateChange.event; } - private _onSortComplete = new Emitter>(); + private _onSortComplete = this._register(new Emitter>()); get onSortComplete(): Event> { return this._onSortComplete.event; } constructor( @@ -95,6 +96,7 @@ export class TableDataView implements IDisposableData private _filterFn?: TableFilterFunc, private _cellValueGetter: CellValueGetter = defaultCellValueGetter ) { + super(); if (data) { this._data = data; } else { @@ -303,7 +305,8 @@ export class TableDataView implements IDisposableData return types.isUndefinedOrNull(this._findArray) ? 0 : this._findArray.length; } - dispose() { + override dispose() { + super.dispose(); this._data = []; this._allData = []; this._findArray = []; diff --git a/src/sql/base/parts/tree/browser/treeImpl.ts b/src/sql/base/parts/tree/browser/treeImpl.ts index 8449021c1e..2c9c37454a 100644 --- a/src/sql/base/parts/tree/browser/treeImpl.ts +++ b/src/sql/base/parts/tree/browser/treeImpl.ts @@ -12,6 +12,7 @@ import { INavigator, MappedNavigator } from 'sql/base/common/navigator'; import { Event, Emitter, Relay } from 'vs/base/common/event'; import { Color } from 'vs/base/common/color'; import { mixin } from 'vs/base/common/objects'; +import { Disposable } from 'vs/base/common/lifecycle'; export class TreeContext implements _.ITreeContext { @@ -59,10 +60,9 @@ const defaultStyles: _.ITreeStyles = { listDropBackground: Color.fromHex('#383B3D') }; -export class Tree implements _.ITree { +export class Tree extends Disposable implements _.ITree { private container: HTMLElement; - private context: _.ITreeContext; private model: Model.TreeModel; private view: View.TreeView; @@ -77,10 +77,11 @@ export class Tree implements _.ITree { readonly onDidExpandItem: Event = this._onDidExpandItem.event; private _onDidCollapseItem = new Relay(); readonly onDidCollapseItem: Event = this._onDidCollapseItem.event; - private readonly _onDispose = new Emitter(); + private readonly _onDispose = this._register(new Emitter()); readonly onDidDispose: Event = this._onDispose.event; constructor(container: HTMLElement, configuration: _.ITreeConfiguration, options: _.ITreeOptions = {}) { + super(); this.container = container; mixin(options, defaultStyles, false); @@ -302,7 +303,8 @@ export class Tree implements _.ITree { return new MappedNavigator(this.model.getNavigator(fromElement, subTreeOnly), i => i && i.getElement()); } - public dispose(): void { + public override dispose(): void { + super.dispose(); this._onDispose.fire(); this.model.dispose(); this.view.dispose(); diff --git a/src/sql/base/parts/tree/browser/treeModel.ts b/src/sql/base/parts/tree/browser/treeModel.ts index 68a7ef5573..a346506865 100644 --- a/src/sql/base/parts/tree/browser/treeModel.ts +++ b/src/sql/base/parts/tree/browser/treeModel.ts @@ -14,13 +14,14 @@ interface IMap { [id: string]: T; } interface IItemMap extends IMap { } interface ITraitMap extends IMap { } -export class LockData { +export class LockData extends Disposable { private _item: Item; - private _onDispose?= new Emitter(); + private _onDispose?= this._register(new Emitter()); readonly onDispose: Event = this._onDispose!.event; constructor(item: Item) { + super(); this._item = item; } @@ -28,12 +29,11 @@ export class LockData { return this._item; } - dispose(): void { + override dispose(): void { if (this._onDispose) { this._onDispose.fire(); - this._onDispose.dispose(); - this._onDispose = undefined; } + super.dispose(); } } @@ -233,7 +233,7 @@ export interface IItemChildrenRefreshEvent extends IBaseItemEvent { isNested: boolean; } -export class Item { +export class Item extends Disposable { private registry: ItemRegistry; private context: _.ITreeContext; @@ -259,34 +259,35 @@ export class Item { private traits: { [trait: string]: boolean; }; - private readonly _onDidCreate = new Emitter(); + private readonly _onDidCreate = this._register(new Emitter()); readonly onDidCreate: Event = this._onDidCreate.event; - private readonly _onDidReveal = new Emitter(); + private readonly _onDidReveal = this._register(new Emitter()); readonly onDidReveal: Event = this._onDidReveal.event; - private readonly _onExpand = new Emitter(); + private readonly _onExpand = this._register(new Emitter()); readonly onExpand: Event = this._onExpand.event; - private readonly _onDidExpand = new Emitter(); + private readonly _onDidExpand = this._register(new Emitter()); readonly onDidExpand: Event = this._onDidExpand.event; - private readonly _onCollapse = new Emitter(); + private readonly _onCollapse = this._register(new Emitter()); readonly onCollapse: Event = this._onCollapse.event; - private readonly _onDidCollapse = new Emitter(); + private readonly _onDidCollapse = this._register(new Emitter()); readonly onDidCollapse: Event = this._onDidCollapse.event; - private readonly _onDidAddTrait = new Emitter(); + private readonly _onDidAddTrait = this._register(new Emitter()); readonly onDidAddTrait: Event = this._onDidAddTrait.event; - private readonly _onDidRemoveTrait = new Emitter(); + private readonly _onDidRemoveTrait = this._register(new Emitter()); readonly onDidRemoveTrait: Event = this._onDidRemoveTrait.event; - private readonly _onDidRefresh = new Emitter(); + private readonly _onDidRefresh = this._register(new Emitter()); readonly onDidRefresh: Event = this._onDidRefresh.event; - private readonly _onRefreshChildren = new Emitter(); + private readonly _onRefreshChildren = this._register(new Emitter()); readonly onRefreshChildren: Event = this._onRefreshChildren.event; - private readonly _onDidRefreshChildren = new Emitter(); + private readonly _onDidRefreshChildren = this._register(new Emitter()); readonly onDidRefreshChildren: Event = this._onDidRefreshChildren.event; - private readonly _onDidDispose = new Emitter(); + private readonly _onDidDispose = this._register(new Emitter()); readonly onDidDispose: Event = this._onDidDispose.event; private _isDisposed: boolean; constructor(id: string, registry: ItemRegistry, context: _.ITreeContext, lock: Lock, element: any) { + super(); this.registry = registry; this.context = context; this.lock = lock; @@ -689,9 +690,8 @@ export class Item { return this._isDisposed; } - public dispose(): void { + public override dispose(): void { this.forEachChild((child) => child.dispose()); - this.parent = null; this.previous = null; this.next = null; @@ -702,19 +702,7 @@ export class Item { this.registry.deregister(this); - this._onDidCreate.dispose(); - this._onDidReveal.dispose(); - this._onExpand.dispose(); - this._onDidExpand.dispose(); - this._onCollapse.dispose(); - this._onDidCollapse.dispose(); - this._onDidAddTrait.dispose(); - this._onDidRemoveTrait.dispose(); - this._onDidRefresh.dispose(); - this._onRefreshChildren.dispose(); - this._onDidRefreshChildren.dispose(); - this._onDidDispose.dispose(); - + super.dispose(); this._isDisposed = true; } } @@ -859,54 +847,55 @@ export interface IRefreshEvent extends IBaseEvent { recursive: boolean; } -export class TreeModel { +export class TreeModel extends Disposable { private context: _.ITreeContext; private lock!: Lock; private input: Item | null; - private registry: ItemRegistry = new ItemRegistry(); + private registry: ItemRegistry = this._register(new ItemRegistry()); private registryDisposable: IDisposable = Disposable.None; private traitsToItems: ITraitMap; - private readonly _onSetInput = new Emitter(); + private readonly _onSetInput = this._register(new Emitter()); readonly onSetInput: Event = this._onSetInput.event; - private readonly _onDidSetInput = new Emitter(); + private readonly _onDidSetInput = this._register(new Emitter()); readonly onDidSetInput: Event = this._onDidSetInput.event; - private readonly _onRefresh = new Emitter(); + private readonly _onRefresh = this._register(new Emitter()); readonly onRefresh: Event = this._onRefresh.event; - private readonly _onDidRefresh = new Emitter(); + private readonly _onDidRefresh = this._register(new Emitter()); readonly onDidRefresh: Event = this._onDidRefresh.event; - private readonly _onDidHighlight = new Emitter<_.IHighlightEvent>(); + private readonly _onDidHighlight = this._register(new Emitter<_.IHighlightEvent>()); readonly onDidHighlight: Event<_.IHighlightEvent> = this._onDidHighlight.event; - private readonly _onDidSelect = new Emitter<_.ISelectionEvent>(); + private readonly _onDidSelect = this._register(new Emitter<_.ISelectionEvent>()); readonly onDidSelect: Event<_.ISelectionEvent> = this._onDidSelect.event; - private readonly _onDidFocus = new Emitter<_.IFocusEvent>(); + private readonly _onDidFocus = this._register(new Emitter<_.IFocusEvent>()); readonly onDidFocus: Event<_.IFocusEvent> = this._onDidFocus.event; - private _onDidRevealItem = new Relay(); + private _onDidRevealItem = this._register(new Relay()); readonly onDidRevealItem: Event = this._onDidRevealItem.event; - private _onExpandItem = new Relay(); + private _onExpandItem = this._register(new Relay()); readonly onExpandItem: Event = this._onExpandItem.event; - private _onDidExpandItem = new Relay(); + private _onDidExpandItem = this._register(new Relay()); readonly onDidExpandItem: Event = this._onDidExpandItem.event; - private _onCollapseItem = new Relay(); + private _onCollapseItem = this._register(new Relay()); readonly onCollapseItem: Event = this._onCollapseItem.event; - private _onDidCollapseItem = new Relay(); + private _onDidCollapseItem = this._register(new Relay()); readonly onDidCollapseItem: Event = this._onDidCollapseItem.event; - private _onDidAddTraitItem = new Relay(); + private _onDidAddTraitItem = this._register(new Relay()); readonly onDidAddTraitItem: Event = this._onDidAddTraitItem.event; - private _onDidRemoveTraitItem = new Relay(); + private _onDidRemoveTraitItem = this._register(new Relay()); readonly onDidRemoveTraitItem: Event = this._onDidRemoveTraitItem.event; - private _onDidRefreshItem = new Relay(); + private _onDidRefreshItem = this._register(new Relay()); readonly onDidRefreshItem: Event = this._onDidRefreshItem.event; - private _onRefreshItemChildren = new Relay(); + private _onRefreshItemChildren = this._register(new Relay()); readonly onRefreshItemChildren: Event = this._onRefreshItemChildren.event; - private _onDidRefreshItemChildren = new Relay(); + private _onDidRefreshItemChildren = this._register(new Relay()); readonly onDidRefreshItemChildren: Event = this._onDidRefreshItemChildren.event; - private _onDidDisposeItem = new Relay(); + private _onDidDisposeItem = this._register(new Relay()); readonly onDidDisposeItem: Event = this._onDidDisposeItem.event; constructor(context: _.ITreeContext) { + super(); this.context = context; this.input = null; this.traitsToItems = {}; @@ -1471,26 +1460,4 @@ export class TreeModel { } return elements; } - - public dispose(): void { - this.registry.dispose(); - this._onSetInput.dispose(); - this._onDidSetInput.dispose(); - this._onRefresh.dispose(); - this._onDidRefresh.dispose(); - this._onDidHighlight.dispose(); - this._onDidSelect.dispose(); - this._onDidFocus.dispose(); - this._onDidRevealItem.dispose(); - this._onExpandItem.dispose(); - this._onDidExpandItem.dispose(); - this._onCollapseItem.dispose(); - this._onDidCollapseItem.dispose(); - this._onDidAddTraitItem.dispose(); - this._onDidRemoveTraitItem.dispose(); - this._onDidRefreshItem.dispose(); - this._onRefreshItemChildren.dispose(); - this._onDidRefreshItemChildren.dispose(); - this._onDidDisposeItem.dispose(); - } } diff --git a/src/sql/base/parts/tree/browser/treeView.ts b/src/sql/base/parts/tree/browser/treeView.ts index 1e93247f59..198754a37a 100644 --- a/src/sql/base/parts/tree/browser/treeView.ts +++ b/src/sql/base/parts/tree/browser/treeView.ts @@ -447,13 +447,13 @@ export class TreeView extends HeightMap { private highlightedItemWasDraggable: boolean = false; private onHiddenScrollTop: number | null = null; - private readonly _onDOMFocus = new Emitter(); + private readonly _onDOMFocus = this._register(new Emitter()); readonly onDOMFocus: Event = this._onDOMFocus.event; - private readonly _onDOMBlur = new Emitter(); + private readonly _onDOMBlur = this._register(new Emitter()); readonly onDOMBlur: Event = this._onDOMBlur.event; - private readonly _onDidScroll = new Emitter(); + private readonly _onDidScroll = this._register(new Emitter()); readonly onDidScroll: Event = this._onDidScroll.event; constructor(context: _.ITreeContext, container: HTMLElement) { diff --git a/src/sql/base/parts/tree/browser/treeViewModel.ts b/src/sql/base/parts/tree/browser/treeViewModel.ts index 98efb01ea1..a0576e708b 100644 --- a/src/sql/base/parts/tree/browser/treeViewModel.ts +++ b/src/sql/base/parts/tree/browser/treeViewModel.ts @@ -6,6 +6,7 @@ import { onUnexpectedError } from 'vs/base/common/errors'; import { ArrayNavigator, INavigator } from 'vs/base/common/navigator'; import { Item } from './treeModel'; +import { Disposable } from 'vs/base/common/lifecycle'; export interface IViewItem { model: Item; @@ -14,7 +15,7 @@ export interface IViewItem { width: number; } -export class HeightMap { +export class HeightMap extends Disposable { private heightMap: IViewItem[] = []; private indexes: { [item: string]: number; } = {}; @@ -231,7 +232,8 @@ export class HeightMap { throw new Error('not implemented'); } - dispose(): void { + override dispose(): void { + super.dispose(); this.heightMap = []; this.indexes = {}; } diff --git a/src/sql/base/parts/tree/test/browser/treeModel.test.ts b/src/sql/base/parts/tree/test/browser/treeModel.test.ts index 35cd92c93f..9df9d8809a 100644 --- a/src/sql/base/parts/tree/test/browser/treeModel.test.ts +++ b/src/sql/base/parts/tree/test/browser/treeModel.test.ts @@ -10,6 +10,7 @@ import * as model from 'sql/base/parts/tree/browser/treeModel'; import * as TreeDefaults from 'sql/base/parts/tree/browser/treeDefaults'; import { Event, Emitter } from 'vs/base/common/event'; import { timeout } from 'vs/base/common/async'; +import { Disposable } from 'vs/base/common/lifecycle'; class FakeRenderer { @@ -1076,18 +1077,19 @@ suite('TreeModel - Traits', () => { }); }); -class DynamicModel implements _.IDataSource { +class DynamicModel extends Disposable implements _.IDataSource { private data: any; public promiseFactory: { (): Promise; } | null; - private readonly _onGetChildren = new Emitter(); + private readonly _onGetChildren = this._register(new Emitter()); readonly onGetChildren: Event = this._onGetChildren.event; - private readonly _onDidGetChildren = new Emitter(); + private readonly _onDidGetChildren = this._register(new Emitter()); readonly onDidGetChildren: Event = this._onDidGetChildren.event; constructor() { + super(); this.data = { root: [] }; this.promiseFactory = null; } diff --git a/src/sql/base/test/browser/ui/editableDropdown/dropdown.test.ts b/src/sql/base/test/browser/ui/editableDropdown/dropdown.test.ts index 1378bbc11a..0b337c5a21 100644 --- a/src/sql/base/test/browser/ui/editableDropdown/dropdown.test.ts +++ b/src/sql/base/test/browser/ui/editableDropdown/dropdown.test.ts @@ -27,6 +27,7 @@ suite('Editable dropdown tests', () => { test('default value for editable dropdown is empty', () => { const dropdown = new Dropdown(container, undefined, options); assert.strictEqual(dropdown.value, ''); + dropdown.dispose(); }); test('changing value through code fires onValueChange event', () => { @@ -42,6 +43,7 @@ suite('Editable dropdown tests', () => { assert.strictEqual(count, 1, 'onValueChange event should not be fired for setting the same value again'); dropdown.value = options.values[1]; assert.strictEqual(count, 2, 'onValueChange event was not fired for setting a new value of the dropdown'); + dropdown.dispose(); }); test('changing value through input text fires onValue Change event', () => { @@ -67,6 +69,7 @@ suite('Editable dropdown tests', () => { dropdown.fireOnTextChange = false; dropdown.input.value = options.values[0]; assert.strictEqual(count, 3, 'onValueChange event was fired with input box value change even after setting the fireOnTextChange to false'); + dropdown.dispose(); }); test('selecting same dropdown value again after changing text field should update text field', () => { @@ -75,5 +78,6 @@ suite('Editable dropdown tests', () => { dropdown.input.value = 'NotARealValue'; dropdown.value = options.values[0]; assert.strictEqual(dropdown.input.value, options.values[0]); + dropdown.dispose(); }); }); diff --git a/src/sql/base/test/browser/ui/selectBox/selectBox.test.ts b/src/sql/base/test/browser/ui/selectBox/selectBox.test.ts index 2efe8b0718..2974a531d6 100644 --- a/src/sql/base/test/browser/ui/selectBox/selectBox.test.ts +++ b/src/sql/base/test/browser/ui/selectBox/selectBox.test.ts @@ -16,8 +16,8 @@ suite('Select Box tests', () => { test('default value', () => { const sb = new SelectBox(options, options[1].value, {}, undefined!, undefined!, undefined!); - assert(sb.value === options[1].value); + sb.dispose(); }); test('values change', () => { @@ -34,6 +34,7 @@ suite('Select Box tests', () => { sb.setOptions(newOptions); assert(equals(sb.values, newOptions.map(s => s.value))); + sb.dispose(); }); test('the selected option changes', () => { @@ -46,6 +47,7 @@ suite('Select Box tests', () => { assert(sb.value === options[0].value); assert(sb.label === options[0].text); + sb.dispose(); }); test('values get auto populated', () => { @@ -53,5 +55,6 @@ suite('Select Box tests', () => { const sb = new SelectBox(newOptions, undefined!, {}, undefined!, undefined!, undefined!); assert(equals(sb.values, newOptions.map(s => s.text))); + sb.dispose(); }); });