mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-01-13 17:22:15 -05:00
Part 3 - Make base browser components disposable (#24244)
This commit is contained in:
@@ -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 });
|
||||
}
|
||||
|
||||
|
||||
@@ -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.');
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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 = [];
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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 = {};
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -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();
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user