Part 3 - Make base browser components disposable (#24244)

This commit is contained in:
Cheena Malhotra
2023-08-29 14:19:22 -07:00
committed by GitHub
parent 362290f8ec
commit f0f4f32a69
16 changed files with 136 additions and 152 deletions

View File

@@ -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 });
}

View File

@@ -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<T> {
getLength(): number;
@@ -79,7 +80,7 @@ class DataWindow<T> {
}
}
export class VirtualizedCollection<T extends Slick.SlickData> implements IObservableCollection<T> {
export class VirtualizedCollection<T extends Slick.SlickData> extends Disposable implements IObservableCollection<T> {
private _bufferWindowBefore: DataWindow<T>;
private _window: DataWindow<T>;
private _bufferWindowAfter: DataWindow<T>;
@@ -93,21 +94,16 @@ export class VirtualizedCollection<T extends Slick.SlickData> implements IObserv
private length: number,
loadFn: (offset: number, count: number) => Thenable<T[]>
) {
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<T extends Slick.SlickData> implements IObserv
}
}
export class AsyncDataProvider<T extends Slick.SlickData> implements IDisposableDataProvider<T> {
export class AsyncDataProvider<T extends Slick.SlickData> extends Disposable implements IDisposableDataProvider<T> {
private _onFilterStateChange = new Emitter<void>();
private _onFilterStateChange = this._register(new Emitter<void>());
get onFilterStateChange(): Event<void> { return this._onFilterStateChange.event; }
private _onSortComplete = new Emitter<Slick.OnSortEventArgs<T>>();
private _onSortComplete = this._register(new Emitter<Slick.OnSortEventArgs<T>>());
get onSortComplete(): Event<Slick.OnSortEventArgs<T>> { return this._onSortComplete.event; }
constructor(public dataRows: IObservableCollection<T>) { }
constructor(public dataRows: IObservableCollection<T>) {
super();
this._register(dataRows);
}
public get isDataInMemory(): boolean {
return false;
@@ -250,10 +249,6 @@ export class AsyncDataProvider<T extends Slick.SlickData> implements IDisposable
return this.dataRows.getLength();
}
dispose() {
this.dataRows.dispose();
}
getItems(): T[] {
throw new Error('Method not supported.');
}

View File

@@ -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<T extends Slick.SlickData> implements IDisposableDataProvider<T> {
export class HybridDataProvider<T extends Slick.SlickData> extends Disposable implements IDisposableDataProvider<T> {
private _asyncDataProvider: AsyncDataProvider<T>;
private _tableDataProvider: TableDataView<T>;
private _dataCached: boolean = false;
private _disposableStore = new DisposableStore();
private _onFilterStateChange = new Emitter<void>();
private _onFilterStateChange = this._register(new Emitter<void>());
get onFilterStateChange(): Event<void> { return this._onFilterStateChange.event; }
private _onSortComplete = new Emitter<Slick.OnSortEventArgs<T>>();
private _onSortComplete = this._register(new Emitter<Slick.OnSortEventArgs<T>>());
get onSortComplete(): Event<Slick.OnSortEventArgs<T>> { return this._onSortComplete.event; }
constructor(dataRows: IObservableCollection<T>,
@@ -37,22 +36,23 @@ export class HybridDataProvider<T extends Slick.SlickData> implements IDisposabl
sortFn: TableSortFunc<T>,
valueGetter: CellValueGetter,
private readonly _options: HybridDataProviderOptions) {
super();
this._asyncDataProvider = new AsyncDataProvider<T>(dataRows);
this._tableDataProvider = new TableDataView<T>(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<T extends Slick.SlickData> implements IDisposabl
this._asyncDataProvider.dataRows = value;
}
public dispose(): void {
this._disposableStore.dispose();
}
public getLength(): number {
return this.provider.getLength();
}

View File

@@ -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<T extends Slick.SlickData> {
export interface CheckBoxColumnOptions extends BaseTableColumnOptions {
}
export class CheckBoxColumn<T extends Slick.SlickData> implements Slick.Plugin<T>, TableColumn<T> {
export class CheckBoxColumn<T extends Slick.SlickData> extends Disposable implements Slick.Plugin<T>, TableColumn<T> {
private _handler = new Slick.EventHandler();
private _grid!: Slick.Grid<T>;
private _onChange = new Emitter<CheckBoxChangedEventArgs<T>>();
private _onChange = this._register(new Emitter<CheckBoxChangedEventArgs<T>>());
public onChange = this._onChange.event;
constructor(private options: CheckBoxColumnOptions) {
super();
}
public init(grid: Slick.Grid<T>): void {

View File

@@ -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<T extends Slick.SlickData> implements Slick.Plugin<T> {
export class CheckboxSelectColumn<T extends Slick.SlickData> extends Disposable implements Slick.Plugin<T> {
private _grid!: Slick.Grid<T>;
private _handler = new Slick.EventHandler();
private _options: ICheckboxSelectColumnOptions;
public index: number;
private _headerCheckbox: HTMLInputElement | undefined;
private _onChange = new Emitter<ICheckboxCellActionEventArgs>();
private _onCheckAllChange = new Emitter<ICheckAllActionEventArgs>();
private _onChange = this._register(new Emitter<ICheckboxCellActionEventArgs>());
private _onCheckAllChange = this._register(new Emitter<ICheckAllActionEventArgs>());
public readonly onChange: vsEvent<ICheckboxCellActionEventArgs> = this._onChange.event;
public readonly onCheckAllChange: vsEvent<ICheckAllActionEventArgs> = 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;

View File

@@ -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<T> implements Slick.Plugin<T> {
export class CopyKeybind<T> extends Disposable implements Slick.Plugin<T> {
private grid!: Slick.Grid<T>;
private handler = new Slick.EventHandler();
private _onCopy = new Emitter<Slick.Range[]>();
private _onCopy = this._register(new Emitter<Slick.Range[]>());
public onCopy: Event<Slick.Range[]> = this._onCopy.event;
public init(grid: Slick.Grid<T>) {
@@ -56,5 +56,4 @@ export class CopyKeybind<T> implements Slick.Plugin<T> {
e.browserEvent.stopImmediatePropagation
}
}
}

View File

@@ -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<T extends Slick.SlickData> {
export class HeaderFilter<T extends Slick.SlickData> extends Disposable {
public onFilterApplied = new Slick.Event<{ grid: Slick.Grid<T>, column: FilterableColumn<T> }>();
public onCommand = new Slick.Event<CommandEventArgs<T>>();
@@ -81,6 +81,7 @@ export class HeaderFilter<T extends Slick.SlickData> {
private listContainer?: HTMLElement;
constructor(private readonly options: ITableFilterOptions, private readonly contextViewProvider: IContextViewProvider, private readonly notificationProvider?: NotificationProvider) {
super();
}
public init(grid: Slick.Grid<T>): void {
@@ -198,10 +199,10 @@ export class HeaderFilter<T extends Slick.SlickData> {
});
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<T extends Slick.SlickData> {
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<void> {
@@ -262,7 +263,9 @@ export class HeaderFilter<T extends Slick.SlickData> {
// 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<T extends Slick.SlickData> {
}
}
class TableFilterListElement {
private readonly _onCheckStateChanged = new Emitter<boolean>();
class TableFilterListElement extends Disposable {
private readonly _onCheckStateChanged = this._register(new Emitter<boolean>());
private _checked: boolean;
constructor(val: string, checked: boolean) {
super();
this.value = val;
this._checked = checked;

View File

@@ -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<T extends Slick.SlickData> {
readonly definition: Slick.Column<T>;
@@ -25,13 +26,14 @@ export interface ClickableColumnOptions {
enabledField?: string;
}
export abstract class BaseClickableColumn<T extends Slick.SlickData> implements Slick.Plugin<T>, TableColumn<T> {
export abstract class BaseClickableColumn<T extends Slick.SlickData> extends Disposable implements Slick.Plugin<T>, TableColumn<T> {
protected _handler = new Slick.EventHandler();
protected _grid!: Slick.Grid<T>;
private _onClick = new Emitter<TableCellClickEventArgs<T>>();
private _onClick = this._register(new Emitter<TableCellClickEventArgs<T>>());
public onClick = this._onClick.event;
constructor(private readonly _options: ClickableColumnOptions) {
super();
}
public init(grid: Slick.Grid<T>): void {
@@ -45,6 +47,9 @@ export abstract class BaseClickableColumn<T extends Slick.SlickData> implements
this._handler.unsubscribeAll();
}
public override dispose(): void {
this.destroy();
}
/**
* Returns the column definition.
* Note when implementing this abstract getter:

View File

@@ -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<T extends Slick.SlickData>(data: T[], columns: Fil
return filteredData;
}
export class TableDataView<T extends Slick.SlickData> implements IDisposableDataProvider<T> {
export class TableDataView<T extends Slick.SlickData> extends Disposable implements IDisposableDataProvider<T> {
//The data exposed publicly, when filter is enabled, _data holds the filtered data.
private _data: Array<T>;
//Used when filtering is enabled, _allData holds the complete set of data.
@@ -76,16 +77,16 @@ export class TableDataView<T extends Slick.SlickData> implements IDisposableData
private _filterEnabled: boolean;
private _currentColumnFilters: FilterableColumn<T>[];
private _onRowCountChange = new Emitter<number>();
private _onRowCountChange = this._register(new Emitter<number>());
get onRowCountChange(): Event<number> { return this._onRowCountChange.event; }
private _onFindCountChange = new Emitter<number>();
private _onFindCountChange = this._register(new Emitter<number>());
get onFindCountChange(): Event<number> { return this._onFindCountChange.event; }
private _onFilterStateChange = new Emitter<void>();
private _onFilterStateChange = this._register(new Emitter<void>());
get onFilterStateChange(): Event<void> { return this._onFilterStateChange.event; }
private _onSortComplete = new Emitter<Slick.OnSortEventArgs<T>>();
private _onSortComplete = this._register(new Emitter<Slick.OnSortEventArgs<T>>());
get onSortComplete(): Event<Slick.OnSortEventArgs<T>> { return this._onSortComplete.event; }
constructor(
@@ -95,6 +96,7 @@ export class TableDataView<T extends Slick.SlickData> implements IDisposableData
private _filterFn?: TableFilterFunc<T>,
private _cellValueGetter: CellValueGetter = defaultCellValueGetter
) {
super();
if (data) {
this._data = data;
} else {
@@ -303,7 +305,8 @@ export class TableDataView<T extends Slick.SlickData> implements IDisposableData
return types.isUndefinedOrNull(this._findArray) ? 0 : this._findArray.length;
}
dispose() {
override dispose() {
super.dispose();
this._data = [];
this._allData = [];
this._findArray = [];

View File

@@ -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<Model.IItemExpandEvent> = this._onDidExpandItem.event;
private _onDidCollapseItem = new Relay<Model.IItemCollapseEvent>();
readonly onDidCollapseItem: Event<Model.IItemCollapseEvent> = this._onDidCollapseItem.event;
private readonly _onDispose = new Emitter<void>();
private readonly _onDispose = this._register(new Emitter<void>());
readonly onDidDispose: Event<void> = 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();

View File

@@ -14,13 +14,14 @@ interface IMap<T> { [id: string]: T; }
interface IItemMap extends IMap<Item> { }
interface ITraitMap extends IMap<IItemMap> { }
export class LockData {
export class LockData extends Disposable {
private _item: Item;
private _onDispose?= new Emitter<void>();
private _onDispose?= this._register(new Emitter<void>());
readonly onDispose: Event<void> = 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<Item>();
private readonly _onDidCreate = this._register(new Emitter<Item>());
readonly onDidCreate: Event<Item> = this._onDidCreate.event;
private readonly _onDidReveal = new Emitter<IItemRevealEvent>();
private readonly _onDidReveal = this._register(new Emitter<IItemRevealEvent>());
readonly onDidReveal: Event<IItemRevealEvent> = this._onDidReveal.event;
private readonly _onExpand = new Emitter<IItemExpandEvent>();
private readonly _onExpand = this._register(new Emitter<IItemExpandEvent>());
readonly onExpand: Event<IItemExpandEvent> = this._onExpand.event;
private readonly _onDidExpand = new Emitter<IItemExpandEvent>();
private readonly _onDidExpand = this._register(new Emitter<IItemExpandEvent>());
readonly onDidExpand: Event<IItemExpandEvent> = this._onDidExpand.event;
private readonly _onCollapse = new Emitter<IItemCollapseEvent>();
private readonly _onCollapse = this._register(new Emitter<IItemCollapseEvent>());
readonly onCollapse: Event<IItemCollapseEvent> = this._onCollapse.event;
private readonly _onDidCollapse = new Emitter<IItemCollapseEvent>();
private readonly _onDidCollapse = this._register(new Emitter<IItemCollapseEvent>());
readonly onDidCollapse: Event<IItemCollapseEvent> = this._onDidCollapse.event;
private readonly _onDidAddTrait = new Emitter<IItemTraitEvent>();
private readonly _onDidAddTrait = this._register(new Emitter<IItemTraitEvent>());
readonly onDidAddTrait: Event<IItemTraitEvent> = this._onDidAddTrait.event;
private readonly _onDidRemoveTrait = new Emitter<IItemTraitEvent>();
private readonly _onDidRemoveTrait = this._register(new Emitter<IItemTraitEvent>());
readonly onDidRemoveTrait: Event<IItemTraitEvent> = this._onDidRemoveTrait.event;
private readonly _onDidRefresh = new Emitter<Item>();
private readonly _onDidRefresh = this._register(new Emitter<Item>());
readonly onDidRefresh: Event<Item> = this._onDidRefresh.event;
private readonly _onRefreshChildren = new Emitter<IItemChildrenRefreshEvent>();
private readonly _onRefreshChildren = this._register(new Emitter<IItemChildrenRefreshEvent>());
readonly onRefreshChildren: Event<IItemChildrenRefreshEvent> = this._onRefreshChildren.event;
private readonly _onDidRefreshChildren = new Emitter<IItemChildrenRefreshEvent>();
private readonly _onDidRefreshChildren = this._register(new Emitter<IItemChildrenRefreshEvent>());
readonly onDidRefreshChildren: Event<IItemChildrenRefreshEvent> = this._onDidRefreshChildren.event;
private readonly _onDidDispose = new Emitter<Item>();
private readonly _onDidDispose = this._register(new Emitter<Item>());
readonly onDidDispose: Event<Item> = 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<IInputEvent>();
private readonly _onSetInput = this._register(new Emitter<IInputEvent>());
readonly onSetInput: Event<IInputEvent> = this._onSetInput.event;
private readonly _onDidSetInput = new Emitter<IInputEvent>();
private readonly _onDidSetInput = this._register(new Emitter<IInputEvent>());
readonly onDidSetInput: Event<IInputEvent> = this._onDidSetInput.event;
private readonly _onRefresh = new Emitter<IRefreshEvent>();
private readonly _onRefresh = this._register(new Emitter<IRefreshEvent>());
readonly onRefresh: Event<IRefreshEvent> = this._onRefresh.event;
private readonly _onDidRefresh = new Emitter<IRefreshEvent>();
private readonly _onDidRefresh = this._register(new Emitter<IRefreshEvent>());
readonly onDidRefresh: Event<IRefreshEvent> = 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<IItemRevealEvent>();
private _onDidRevealItem = this._register(new Relay<IItemRevealEvent>());
readonly onDidRevealItem: Event<IItemRevealEvent> = this._onDidRevealItem.event;
private _onExpandItem = new Relay<IItemExpandEvent>();
private _onExpandItem = this._register(new Relay<IItemExpandEvent>());
readonly onExpandItem: Event<IItemExpandEvent> = this._onExpandItem.event;
private _onDidExpandItem = new Relay<IItemExpandEvent>();
private _onDidExpandItem = this._register(new Relay<IItemExpandEvent>());
readonly onDidExpandItem: Event<IItemExpandEvent> = this._onDidExpandItem.event;
private _onCollapseItem = new Relay<IItemCollapseEvent>();
private _onCollapseItem = this._register(new Relay<IItemCollapseEvent>());
readonly onCollapseItem: Event<IItemCollapseEvent> = this._onCollapseItem.event;
private _onDidCollapseItem = new Relay<IItemCollapseEvent>();
private _onDidCollapseItem = this._register(new Relay<IItemCollapseEvent>());
readonly onDidCollapseItem: Event<IItemCollapseEvent> = this._onDidCollapseItem.event;
private _onDidAddTraitItem = new Relay<IItemTraitEvent>();
private _onDidAddTraitItem = this._register(new Relay<IItemTraitEvent>());
readonly onDidAddTraitItem: Event<IItemTraitEvent> = this._onDidAddTraitItem.event;
private _onDidRemoveTraitItem = new Relay<IItemTraitEvent>();
private _onDidRemoveTraitItem = this._register(new Relay<IItemTraitEvent>());
readonly onDidRemoveTraitItem: Event<IItemTraitEvent> = this._onDidRemoveTraitItem.event;
private _onDidRefreshItem = new Relay<Item>();
private _onDidRefreshItem = this._register(new Relay<Item>());
readonly onDidRefreshItem: Event<Item> = this._onDidRefreshItem.event;
private _onRefreshItemChildren = new Relay<IItemChildrenRefreshEvent>();
private _onRefreshItemChildren = this._register(new Relay<IItemChildrenRefreshEvent>());
readonly onRefreshItemChildren: Event<IItemChildrenRefreshEvent> = this._onRefreshItemChildren.event;
private _onDidRefreshItemChildren = new Relay<IItemChildrenRefreshEvent>();
private _onDidRefreshItemChildren = this._register(new Relay<IItemChildrenRefreshEvent>());
readonly onDidRefreshItemChildren: Event<IItemChildrenRefreshEvent> = this._onDidRefreshItemChildren.event;
private _onDidDisposeItem = new Relay<Item>();
private _onDidDisposeItem = this._register(new Relay<Item>());
readonly onDidDisposeItem: Event<Item> = 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();
}
}

View File

@@ -447,13 +447,13 @@ export class TreeView extends HeightMap {
private highlightedItemWasDraggable: boolean = false;
private onHiddenScrollTop: number | null = null;
private readonly _onDOMFocus = new Emitter<void>();
private readonly _onDOMFocus = this._register(new Emitter<void>());
readonly onDOMFocus: Event<void> = this._onDOMFocus.event;
private readonly _onDOMBlur = new Emitter<void>();
private readonly _onDOMBlur = this._register(new Emitter<void>());
readonly onDOMBlur: Event<void> = this._onDOMBlur.event;
private readonly _onDidScroll = new Emitter<void>();
private readonly _onDidScroll = this._register(new Emitter<void>());
readonly onDidScroll: Event<void> = this._onDidScroll.event;
constructor(context: _.ITreeContext, container: HTMLElement) {

View File

@@ -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 = {};
}

View File

@@ -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<any>; } | null;
private readonly _onGetChildren = new Emitter<any>();
private readonly _onGetChildren = this._register(new Emitter<any>());
readonly onGetChildren: Event<any> = this._onGetChildren.event;
private readonly _onDidGetChildren = new Emitter<any>();
private readonly _onDidGetChildren = this._register(new Emitter<any>());
readonly onDidGetChildren: Event<any> = this._onDidGetChildren.event;
constructor() {
super();
this.data = { root: [] };
this.promiseFactory = null;
}

View File

@@ -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();
});
});

View File

@@ -16,8 +16,8 @@ suite('Select Box tests', () => {
test('default value', () => {
const sb = new SelectBox(options, options[1].value, <ISelectBoxStyles>{}, 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!, <ISelectBoxStyles>{}, undefined!, undefined!, undefined!);
assert(equals(sb.values, newOptions.map(s => s.text)));
sb.dispose();
});
});