diff options
Diffstat (limited to 'src')
22 files changed, 408 insertions, 297 deletions
diff --git a/src/vs/base/browser/ui/list/listWidget.ts b/src/vs/base/browser/ui/list/listWidget.ts index 16f8e590c29..5df3143479c 100644 --- a/src/vs/base/browser/ui/list/listWidget.ts +++ b/src/vs/base/browser/ui/list/listWidget.ts @@ -631,11 +631,11 @@ export class List<T> implements ISpliceable<T>, IDisposable { return mapEvent(this._onPin.event, indexes => this.toListEvent({ indexes })); } - readonly onDOMFocus: Event<void>; - readonly onDOMBlur: Event<void>; + readonly onDidFocus: Event<void>; + readonly onDidBlur: Event<void>; - private _onDispose = new Emitter<void>(); - get onDispose(): Event<void> { return this._onDispose.event; } + private _onDidDispose = new Emitter<void>(); + get onDidDispose(): Event<void> { return this._onDidDispose.event; } constructor( container: HTMLElement, @@ -666,10 +666,10 @@ export class List<T> implements ISpliceable<T>, IDisposable { this.view ]); - this.disposables = [this.focus, this.selection, this.view, this._onDispose]; + this.disposables = [this.focus, this.selection, this.view, this._onDidDispose]; - this.onDOMFocus = mapEvent(domEvent(this.view.domNode, 'focus', true), () => null); - this.onDOMBlur = mapEvent(domEvent(this.view.domNode, 'blur', true), () => null); + this.onDidFocus = mapEvent(domEvent(this.view.domNode, 'focus', true), () => null); + this.onDidBlur = mapEvent(domEvent(this.view.domNode, 'blur', true), () => null); if (typeof options.keyboardSupport !== 'boolean' || options.keyboardSupport) { const controller = new KeyboardController(this, this.view); @@ -972,7 +972,7 @@ export class List<T> implements ISpliceable<T>, IDisposable { } dispose(): void { - this._onDispose.fire(); + this._onDidDispose.fire(); this.disposables = dispose(this.disposables); } } diff --git a/src/vs/base/common/event.ts b/src/vs/base/common/event.ts index db293abd0d7..8543a6fcd3c 100644 --- a/src/vs/base/common/event.ts +++ b/src/vs/base/common/event.ts @@ -552,7 +552,7 @@ export function echo<T>(event: Event<T>, nextTick = false, buffer: T[] = []): Ev export class Relay<T> implements IDisposable { private emitter = new Emitter<T>(); - readonly output: Event<T> = this.emitter.event; + readonly event: Event<T> = this.emitter.event; private disposable: IDisposable = EmptyDisposable; diff --git a/src/vs/base/parts/quickopen/browser/quickOpenWidget.ts b/src/vs/base/parts/quickopen/browser/quickOpenWidget.ts index 5018c59b31b..6a0ed9e9a70 100644 --- a/src/vs/base/parts/quickopen/browser/quickOpenWidget.ts +++ b/src/vs/base/parts/quickopen/browser/quickOpenWidget.ts @@ -8,7 +8,6 @@ import 'vs/css!./quickopen'; import nls = require('vs/nls'); import { TPromise } from 'vs/base/common/winjs.base'; import platform = require('vs/base/common/platform'); -import { EventType } from 'vs/base/common/events'; import types = require('vs/base/common/types'); import errors = require('vs/base/common/errors'); import { IQuickNavigateConfiguration, IAutoFocus, IEntryRunContext, IModel, Mode } from 'vs/base/parts/quickopen/common/quickOpen'; @@ -251,11 +250,11 @@ export class QuickOpenWidget implements IModelProvider { this.treeElement = this.tree.getHTMLElement(); // Handle Focus and Selection event - this.toUnbind.push(this.tree.addListener(EventType.FOCUS, (event: IFocusEvent) => { + this.toUnbind.push(this.tree.onDidChangeFocus((event: IFocusEvent) => { this.elementFocused(event.focus, event); })); - this.toUnbind.push(this.tree.addListener(EventType.SELECTION, (event: ISelectionEvent) => { + this.toUnbind.push(this.tree.onDidChangeSelection((event: ISelectionEvent) => { if (event.selection && event.selection.length > 0) { this.elementSelected(event.selection[0], event); } diff --git a/src/vs/base/parts/tree/browser/tree.ts b/src/vs/base/parts/tree/browser/tree.ts index 5deb416f417..9ed4d108d35 100644 --- a/src/vs/base/parts/tree/browser/tree.ts +++ b/src/vs/base/parts/tree/browser/tree.ts @@ -6,7 +6,6 @@ import WinJS = require('vs/base/common/winjs.base'); import Touch = require('vs/base/browser/touch'); -import Events = require('vs/base/common/eventEmitter'); import Mouse = require('vs/base/browser/mouseEvent'); import Keyboard = require('vs/base/browser/keyboardEvent'); import { INavigator } from 'vs/base/common/iterator'; @@ -14,15 +13,18 @@ import { ScrollbarVisibility } from 'vs/base/common/scrollable'; import Event from 'vs/base/common/event'; import { IAction, IActionItem } from 'vs/base/common/actions'; import { Color } from 'vs/base/common/color'; - -export interface ITree extends Events.IEventEmitter { - - emit(eventType: string, data?: any): void; - - onDOMFocus: Event<void>; - onDOMBlur: Event<void>; - onHighlightChange: Event<void>; - onDispose: Event<void>; +import { IItemCollapseEvent, IItemExpandEvent } from 'vs/base/parts/tree/browser/treeModel'; + +export interface ITree { + + onDidFocus: Event<void>; + onDidBlur: Event<void>; + onDidChangeFocus: Event<IFocusEvent>; + onDidChangeSelection: Event<ISelectionEvent>; + onDidChangeHighlight: Event<IHighlightEvent>; + onDidExpandItem: Event<IItemExpandEvent>; + onDidCollapseItem: Event<IItemCollapseEvent>; + onDidDispose: Event<void>; /** * Returns the tree's DOM element. diff --git a/src/vs/base/parts/tree/browser/treeImpl.ts b/src/vs/base/parts/tree/browser/treeImpl.ts index 0397e0171f4..5306affe80c 100644 --- a/src/vs/base/parts/tree/browser/treeImpl.ts +++ b/src/vs/base/parts/tree/browser/treeImpl.ts @@ -7,15 +7,15 @@ import 'vs/css!./tree'; import WinJS = require('vs/base/common/winjs.base'); import TreeDefaults = require('vs/base/parts/tree/browser/treeDefaults'); -import Events = require('vs/base/common/eventEmitter'); import Model = require('vs/base/parts/tree/browser/treeModel'); import View = require('./treeView'); import _ = require('vs/base/parts/tree/browser/tree'); import { INavigator, MappedNavigator } from 'vs/base/common/iterator'; -import Event, { Emitter } from 'vs/base/common/event'; -import Lifecycle = require('vs/base/common/lifecycle'); +import Event, { Emitter, Relay } from 'vs/base/common/event'; import { Color } from 'vs/base/common/color'; import { mixin } from 'vs/base/common/objects'; +import { ISelectionEvent, IFocusEvent, IHighlightEvent } from 'vs/base/parts/tree/browser/tree'; +import { IItemCollapseEvent, IItemExpandEvent } from 'vs/base/parts/tree/browser/treeModel'; export class TreeContext implements _.ITreeContext { @@ -61,7 +61,7 @@ const defaultStyles: _.ITreeStyles = { listDropBackground: Color.fromHex('#383B3D') }; -export class Tree extends Events.EventEmitter implements _.ITree { +export class Tree implements _.ITree { private container: HTMLElement; @@ -69,21 +69,20 @@ export class Tree extends Events.EventEmitter implements _.ITree { private model: Model.TreeModel; private view: View.TreeView; - private _onDispose: Emitter<void>; - private _onHighlightChange: Emitter<void>; - - private toDispose: Lifecycle.IDisposable[]; + private _onDidChangeFocus = new Relay<IFocusEvent>(); + readonly onDidChangeFocus: Event<IFocusEvent> = this._onDidChangeFocus.event; + private _onDidChangeSelection = new Relay<ISelectionEvent>(); + readonly onDidChangeSelection: Event<ISelectionEvent> = this._onDidChangeSelection.event; + private _onHighlightChange = new Relay<IHighlightEvent>(); + readonly onDidChangeHighlight: Event<IHighlightEvent> = this._onHighlightChange.event; + private _onDidExpandItem = new Relay<IItemExpandEvent>(); + readonly onDidExpandItem: Event<IItemExpandEvent> = this._onDidExpandItem.event; + private _onDidCollapseItem = new Relay<IItemCollapseEvent>(); + readonly onDidCollapseItem: Event<IItemCollapseEvent> = this._onDidCollapseItem.event; + private _onDispose = new Emitter<void>(); + readonly onDidDispose: Event<void> = this._onDispose.event; constructor(container: HTMLElement, configuration: _.ITreeConfiguration, options: _.ITreeOptions = {}) { - super(); - - this.toDispose = []; - - this._onDispose = new Emitter<void>(); - this._onHighlightChange = new Emitter<void>(); - - this.toDispose.push(this._onDispose, this._onHighlightChange); - this.container = container; mixin(options, defaultStyles, false); @@ -100,32 +99,25 @@ export class Tree extends Events.EventEmitter implements _.ITree { this.view.setModel(this.model); - this.addEmitter(this.model); - this.addEmitter(this.view); - - this.toDispose.push(this.model.addListener('highlight', () => this._onHighlightChange.fire())); + this._onDidChangeFocus.input = this.model.onDidFocus; + this._onDidChangeSelection.input = this.model.onDidSelect; + this._onHighlightChange.input = this.model.onDidHighlight; + this._onDidExpandItem.input = this.model.onDidExpandItem; + this._onDidCollapseItem.input = this.model.onDidCollapseItem; } public style(styles: _.ITreeStyles): void { this.view.applyStyles(styles); } - get onDOMFocus(): Event<void> { + get onDidFocus(): Event<void> { return this.view && this.view.onDOMFocus; } - get onDOMBlur(): Event<void> { + get onDidBlur(): Event<void> { return this.view && this.view.onDOMBlur; } - get onHighlightChange(): Event<void> { - return this._onHighlightChange && this._onHighlightChange.event; - } - - get onDispose(): Event<void> { - return this._onDispose && this._onDispose.event; - } - public getHTMLElement(): HTMLElement { return this.view.getHTMLElement(); } @@ -380,8 +372,11 @@ export class Tree extends Events.EventEmitter implements _.ITree { this.view = null; } - this.toDispose = Lifecycle.dispose(this.toDispose); - - super.dispose(); + this._onDidChangeFocus.dispose(); + this._onDidChangeSelection.dispose(); + this._onHighlightChange.dispose(); + this._onDidExpandItem.dispose(); + this._onDidCollapseItem.dispose(); + this._onDispose.dispose(); } } diff --git a/src/vs/base/parts/tree/browser/treeModel.ts b/src/vs/base/parts/tree/browser/treeModel.ts index bc6c1e823a2..80db46b1a79 100644 --- a/src/vs/base/parts/tree/browser/treeModel.ts +++ b/src/vs/base/parts/tree/browser/treeModel.ts @@ -9,31 +9,34 @@ import { onUnexpectedError } from 'vs/base/common/errors'; import { IDisposable, combinedDisposable } from 'vs/base/common/lifecycle'; import arrays = require('vs/base/common/arrays'); import { INavigator } from 'vs/base/common/iterator'; -import Events = require('vs/base/common/eventEmitter'); import WinJS = require('vs/base/common/winjs.base'); import _ = require('./tree'); +import Event, { Emitter, once, EventMultiplexer, Relay } from 'vs/base/common/event'; interface IMap<T> { [id: string]: T; } interface IItemMap extends IMap<Item> { } interface ITraitMap extends IMap<IItemMap> { } -export class LockData extends Events.EventEmitter { +export class LockData { private _item: Item; + private _onDispose = new Emitter<void>(); + readonly onDispose: Event<void> = this._onDispose.event; constructor(item: Item) { - super(); - this._item = item; } - public get item(): Item { + get item(): Item { return this._item; } - public dispose(): void { - this.emit('unlock'); - super.dispose(); + dispose(): void { + if (this._onDispose) { + this._onDispose.fire(); + this._onDispose.dispose(); + this._onDispose = null; + } } } @@ -84,7 +87,7 @@ export class Lock { var unbindListener: IDisposable; return new WinJS.TPromise((c, e) => { - unbindListener = lock.addOneTimeListener('unlock', () => { + unbindListener = once(lock.onDispose)(() => { return this.run(item, fn).then(c, e); }); }, () => { unbindListener.dispose(); }); @@ -126,19 +129,55 @@ export class Lock { } } -export class ItemRegistry extends Events.EventEmitter { +export class ItemRegistry { private _isDisposed = false; private items: IMap<{ item: Item; disposable: IDisposable; }>; + private _onDidRevealItem = new EventMultiplexer<IItemRevealEvent>(); + readonly onDidRevealItem: Event<IItemRevealEvent> = this._onDidRevealItem.event; + private _onExpandItem = new EventMultiplexer<IItemExpandEvent>(); + readonly onExpandItem: Event<IItemExpandEvent> = this._onExpandItem.event; + private _onDidExpandItem = new EventMultiplexer<IItemExpandEvent>(); + readonly onDidExpandItem: Event<IItemExpandEvent> = this._onDidExpandItem.event; + private _onCollapseItem = new EventMultiplexer<IItemCollapseEvent>(); + readonly onCollapseItem: Event<IItemCollapseEvent> = this._onCollapseItem.event; + private _onDidCollapseItem = new EventMultiplexer<IItemCollapseEvent>(); + readonly onDidCollapseItem: Event<IItemCollapseEvent> = this._onDidCollapseItem.event; + private _onDidAddTraitItem = new EventMultiplexer<IItemTraitEvent>(); + readonly onDidAddTraitItem: Event<IItemTraitEvent> = this._onDidAddTraitItem.event; + private _onDidRemoveTraitItem = new EventMultiplexer<IItemCollapseEvent>(); + readonly onDidRemoveTraitItem: Event<IItemCollapseEvent> = this._onDidRemoveTraitItem.event; + private _onDidRefreshItem = new EventMultiplexer<Item>(); + readonly onDidRefreshItem: Event<Item> = this._onDidRefreshItem.event; + private _onRefreshItemChildren = new EventMultiplexer<IItemChildrenRefreshEvent>(); + readonly onRefreshItemChildren: Event<IItemChildrenRefreshEvent> = this._onRefreshItemChildren.event; + private _onDidRefreshItemChildren = new EventMultiplexer<IItemChildrenRefreshEvent>(); + readonly onDidRefreshItemChildren: Event<IItemChildrenRefreshEvent> = this._onDidRefreshItemChildren.event; + private _onDidDisposeItem = new EventMultiplexer<Item>(); + readonly onDidDisposeItem: Event<Item> = this._onDidDisposeItem.event; + constructor() { - super(); this.items = {}; } public register(item: Item): void { Assert.ok(!this.isRegistered(item.id), 'item already registered: ' + item.id); - this.items[item.id] = { item, disposable: this.addEmitter(item) }; + + const disposable = combinedDisposable([ + this._onDidRevealItem.add(item.onDidReveal), + this._onExpandItem.add(item.onExpand), + this._onDidExpandItem.add(item.onDidExpand), + this._onCollapseItem.add(item.onCollapse), + this._onDidCollapseItem.add(item.onDidCollapse), + this._onDidAddTraitItem.add(item.onDidAddTrait), + this._onDidRemoveTraitItem.add(item.onDidRemoveTrait), + this._onDidRefreshItem.add(item.onDidRefresh), + this._onRefreshItemChildren.add(item.onRefreshChildren), + this._onDidRefreshItemChildren.add(item.onDidRefreshChildren), + ]); + + this.items[item.id] = { item, disposable }; } public deregister(item: Item): void { @@ -157,8 +196,19 @@ export class ItemRegistry extends Events.EventEmitter { } public dispose(): void { - super.dispose(); this.items = null; + + 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._isDisposed = true; } @@ -174,7 +224,6 @@ export interface IBaseItemEvent { export interface IItemRefreshEvent extends IBaseItemEvent { } export interface IItemExpandEvent extends IBaseItemEvent { } export interface IItemCollapseEvent extends IBaseItemEvent { } -export interface IItemDisposeEvent extends IBaseItemEvent { } export interface IItemTraitEvent extends IBaseItemEvent { trait: string; @@ -188,7 +237,7 @@ export interface IItemChildrenRefreshEvent extends IBaseItemEvent { isNested: boolean; } -export class Item extends Events.EventEmitter { +export class Item { private registry: ItemRegistry; private context: _.ITreeContext; @@ -214,11 +263,34 @@ export class Item extends Events.EventEmitter { private traits: { [trait: string]: boolean; }; + private _onDidCreate = new Emitter<Item>(); + readonly onDidCreate: Event<Item> = this._onDidCreate.event; + private _onDidReveal = new Emitter<IItemRevealEvent>(); + readonly onDidReveal: Event<IItemRevealEvent> = this._onDidReveal.event; + private _onExpand = new Emitter<IItemExpandEvent>(); + readonly onExpand: Event<IItemExpandEvent> = this._onExpand.event; + private _onDidExpand = new Emitter<IItemExpandEvent>(); + readonly onDidExpand: Event<IItemExpandEvent> = this._onDidExpand.event; + private _onCollapse = new Emitter<IItemCollapseEvent>(); + readonly onCollapse: Event<IItemCollapseEvent> = this._onCollapse.event; + private _onDidCollapse = new Emitter<IItemCollapseEvent>(); + readonly onDidCollapse: Event<IItemCollapseEvent> = this._onDidCollapse.event; + private _onDidAddTrait = new Emitter<IItemTraitEvent>(); + readonly onDidAddTrait: Event<IItemTraitEvent> = this._onDidAddTrait.event; + private _onDidRemoveTrait = new Emitter<IItemCollapseEvent>(); + readonly onDidRemoveTrait: Event<IItemCollapseEvent> = this._onDidRemoveTrait.event; + private _onDidRefresh = new Emitter<Item>(); + readonly onDidRefresh: Event<Item> = this._onDidRefresh.event; + private _onRefreshChildren = new Emitter<IItemChildrenRefreshEvent>(); + readonly onRefreshChildren: Event<IItemChildrenRefreshEvent> = this._onRefreshChildren.event; + private _onDidRefreshChildren = new Emitter<IItemChildrenRefreshEvent>(); + readonly onDidRefreshChildren: Event<IItemChildrenRefreshEvent> = this._onDidRefreshChildren.event; + private _onDidDispose = 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; @@ -240,7 +312,7 @@ export class Item extends Events.EventEmitter { this.depth = 0; this.expanded = this.context.dataSource.shouldAutoexpand && this.context.dataSource.shouldAutoexpand(this.context.tree, element); - this.emit('item:create', { item: this }); + this._onDidCreate.fire(this); this.visible = this._isVisible(); this.height = this._getHeight(); @@ -278,7 +350,7 @@ export class Item extends Events.EventEmitter { public reveal(relativeTop: number = null): void { var eventData: IItemRevealEvent = { item: this, relativeTop: relativeTop }; - this.emit('item:reveal', eventData); + this._onDidReveal.fire(eventData); } public expand(): WinJS.Promise { @@ -289,7 +361,7 @@ export class Item extends Events.EventEmitter { var result = this.lock.run(this, () => { var eventData: IItemExpandEvent = { item: this }; var result: WinJS.Promise; - this.emit('item:expanding', eventData); + this._onExpand.fire(eventData); if (this.needsChildrenRefresh) { result = this.refreshChildren(false, true, true); @@ -299,7 +371,7 @@ export class Item extends Events.EventEmitter { return result.then(() => { this._setExpanded(true); - this.emit('item:expanded', eventData); + this._onDidExpand.fire(eventData); return true; }); }); @@ -334,9 +406,9 @@ export class Item extends Events.EventEmitter { return this.lock.run(this, () => { var eventData: IItemCollapseEvent = { item: this }; - this.emit('item:collapsing', eventData); + this._onCollapse.fire(eventData); this._setExpanded(false); - this.emit('item:collapsed', eventData); + this._onDidCollapse.fire(eventData); return WinJS.TPromise.as(true); }); @@ -346,13 +418,13 @@ export class Item extends Events.EventEmitter { public addTrait(trait: string): void { var eventData: IItemTraitEvent = { item: this, trait: trait }; this.traits[trait] = true; - this.emit('item:addTrait', eventData); + this._onDidAddTrait.fire(eventData); } public removeTrait(trait: string): void { var eventData: IItemTraitEvent = { item: this, trait: trait }; delete this.traits[trait]; - this.emit('item:removeTrait', eventData); + this._onDidRemoveTrait.fire(eventData); } public hasTrait(trait: string): boolean { @@ -384,7 +456,7 @@ export class Item extends Events.EventEmitter { var doRefresh = () => { var eventData: IItemChildrenRefreshEvent = { item: this, isNested: safe }; - this.emit('item:childrenRefreshing', eventData); + this._onRefreshChildren.fire(eventData); var childrenPromise: WinJS.Promise; if (this.doesHaveChildren) { @@ -440,20 +512,18 @@ export class Item extends Events.EventEmitter { return result .then(null, onUnexpectedError) - .then(() => this.emit('item:childrenRefreshed', eventData)); + .then(() => this._onDidRefreshChildren.fire(eventData)); }; return safe ? doRefresh() : this.lock.run(this, doRefresh); } private doRefresh(recursive: boolean, safe: boolean = false): WinJS.Promise { - var eventData: IItemRefreshEvent = { item: this }; - this.doesHaveChildren = this.context.dataSource.hasChildren(this.context.tree, this.element); this.height = this._getHeight(); this.setVisible(this._isVisible()); - this.emit('item:refresh', eventData); + this._onDidRefresh.fire(this); return this.refreshChildren(recursive, safe); } @@ -602,11 +672,22 @@ export class Item extends Events.EventEmitter { this.firstChild = null; this.lastChild = null; - var eventData: IItemDisposeEvent = { item: this }; - this.emit('item:dispose', eventData); + this._onDidDispose.fire(this); this.registry.deregister(this); - super.dispose(); + + 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(); this._isDisposed = true; } @@ -788,7 +869,7 @@ export interface IRefreshEvent extends IBaseEvent { recursive: boolean; } -export class TreeModel extends Events.EventEmitter { +export class TreeModel { private context: _.ITreeContext; private lock: Lock; @@ -797,9 +878,45 @@ export class TreeModel extends Events.EventEmitter { private registryDisposable: IDisposable; private traitsToItems: ITraitMap; - constructor(context: _.ITreeContext) { - super(); + private _onSetInput = new Emitter<IInputEvent>(); + readonly onSetInput: Event<IInputEvent> = this._onSetInput.event; + private _onDidSetInput = new Emitter<IInputEvent>(); + readonly onDidSetInput: Event<IInputEvent> = this._onDidSetInput.event; + private _onRefresh = new Emitter<IRefreshEvent>(); + readonly onRefresh: Event<IRefreshEvent> = this._onRefresh.event; + private _onDidRefresh = new Emitter<IRefreshEvent>(); + readonly onDidRefresh: Event<IRefreshEvent> = this._onDidRefresh.event; + private _onDidHighlight = new Emitter<_.IHighlightEvent>(); + readonly onDidHighlight: Event<_.IHighlightEvent> = this._onDidHighlight.event; + private _onDidSelect = new Emitter<_.ISelectionEvent>(); + readonly onDidSelect: Event<_.ISelectionEvent> = this._onDidSelect.event; + private _onDidFocus = new Emitter<_.IFocusEvent>(); + readonly onDidFocus: Event<_.IFocusEvent> = this._onDidFocus.event; + + private _onDidRevealItem = new Relay<IItemRevealEvent>(); + readonly onDidRevealItem: Event<IItemRevealEvent> = this._onDidRevealItem.event; + private _onExpandItem = new Relay<IItemExpandEvent>(); + readonly onExpandItem: Event<IItemExpandEvent> = this._onExpandItem.event; + private _onDidExpandItem = new Relay<IItemExpandEvent>(); + readonly onDidExpandItem: Event<IItemExpandEvent> = this._onDidExpandItem.event; + private _onCollapseItem = new Relay<IItemCollapseEvent>(); + readonly onCollapseItem: Event<IItemCollapseEvent> = this._onCollapseItem.event; + private _onDidCollapseItem = new Relay<IItemCollapseEvent>(); + readonly onDidCollapseItem: Event<IItemCollapseEvent> = this._onDidCollapseItem.event; + private _onDidAddTraitItem = new Relay<IItemTraitEvent>(); + readonly onDidAddTraitItem: Event<IItemTraitEvent> = this._onDidAddTraitItem.event; + private _onDidRemoveTraitItem = new Relay<IItemCollapseEvent>(); + readonly onDidRemoveTraitItem: Event<IItemCollapseEvent> = this._onDidRemoveTraitItem.event; + private _onDidRefreshItem = new Relay<Item>(); + readonly onDidRefreshItem: Event<Item> = this._onDidRefreshItem.event; + private _onRefreshItemChildren = new Relay<IItemChildrenRefreshEvent>(); + readonly onRefreshItemChildren: Event<IItemChildrenRefreshEvent> = this._onRefreshItemChildren.event; + private _onDidRefreshItemChildren = new Relay<IItemChildrenRefreshEvent>(); + readonly onDidRefreshItemChildren: Event<IItemChildrenRefreshEvent> = this._onDidRefreshItemChildren.event; + private _onDidDisposeItem = new Relay<Item>(); + readonly onDidDisposeItem: Event<Item> = this._onDidDisposeItem.event; + constructor(context: _.ITreeContext) { this.context = context; this.input = null; this.traitsToItems = {}; @@ -807,7 +924,7 @@ export class TreeModel extends Events.EventEmitter { public setInput(element: any): WinJS.Promise { var eventData: IInputEvent = { item: this.input }; - this.emit('clearingInput', eventData); + this._onSetInput.fire(eventData); this.setSelection([]); this.setFocus(); @@ -826,18 +943,25 @@ export class TreeModel extends Events.EventEmitter { this.registry = new ItemRegistry(); - this.registryDisposable = combinedDisposable([ - this.addEmitter(this.registry), - this.registry.addListener('item:dispose', (event: IItemDisposeEvent) => { - event.item.getAllTraits() - .forEach(trait => delete this.traitsToItems[trait][event.item.id]); - }) - ]); + this._onDidRevealItem.input = this.registry.onDidRevealItem; + this._onExpandItem.input = this.registry.onExpandItem; + this._onDidExpandItem.input = this.registry.onDidExpandItem; + this._onCollapseItem.input = this.registry.onCollapseItem; + this._onDidCollapseItem.input = this.registry.onDidCollapseItem; + this._onDidAddTraitItem.input = this.registry.onDidAddTraitItem; + this._onDidRemoveTraitItem.input = this.registry.onDidRemoveTraitItem; + this._onDidRefreshItem.input = this.registry.onDidRefreshItem; + this._onRefreshItemChildren.input = this.registry.onRefreshItemChildren; + this._onDidRefreshItemChildren.input = this.registry.onDidRefreshItemChildren; + this._onDidDisposeItem.input = this.registry.onDidDisposeItem; + + this.registryDisposable = this.registry + .onDidDisposeItem(item => item.getAllTraits().forEach(trait => delete this.traitsToItems[trait][item.id])); var id = this.context.dataSource.getId(this.context.tree, element); this.input = new RootItem(id, this.registry, this.context, this.lock, element); eventData = { item: this.input }; - this.emit('setInput', eventData); + this._onDidSetInput.fire(eventData); return this.refresh(this.input); } @@ -853,9 +977,9 @@ export class TreeModel extends Events.EventEmitter { } var eventData: IRefreshEvent = { item: item, recursive: recursive }; - this.emit('refreshing', eventData); + this._onRefresh.fire(eventData); return item.refresh(recursive).then(() => { - this.emit('refreshed', eventData); + this._onDidRefresh.fire(eventData); }); } @@ -1001,7 +1125,7 @@ export class TreeModel extends Events.EventEmitter { public setHighlight(element?: any, eventPayload?: any): void { this.setTraits('highlighted', element ? [element] : []); var eventData: _.IHighlightEvent = { highlight: this.getHighlight(), payload: eventPayload }; - this.emit('highlight', eventData); + this._onDidHighlight.fire(eventData); } public getHighlight(includeHidden?: boolean): any { @@ -1048,7 +1172,7 @@ export class TreeModel extends Events.EventEmitter { public selectAll(elements: any[], eventPayload?: any): void { this.addTraits('selected', elements); var eventData: _.ISelectionEvent = { selection: this.getSelection(), payload: eventPayload }; - this.emit('selection', eventData); + this._onDidSelect.fire(eventData); } public deselect(element: any, eventPayload?: any): void { @@ -1058,19 +1182,19 @@ export class TreeModel extends Events.EventEmitter { public deselectAll(elements: any[], eventPayload?: any): void { this.removeTraits('selected', elements); var eventData: _.ISelectionEvent = { selection: this.getSelection(), payload: eventPayload }; - this.emit('selection', eventData); + this._onDidSelect.fire(eventData); } public setSelection(elements: any[], eventPayload?: any): void { this.setTraits('selected', elements); var eventData: _.ISelectionEvent = { selection: this.getSelection(), payload: eventPayload }; - this.emit('selection', eventData); + this._onDidSelect.fire(eventData); } public toggleSelection(element: any, eventPayload?: any): void { this.toggleTrait('selected', element); var eventData: _.ISelectionEvent = { selection: this.getSelection(), payload: eventPayload }; - this.emit('selection', eventData); + this._onDidSelect.fire(eventData); } public isSelected(element: any): boolean { @@ -1160,7 +1284,7 @@ export class TreeModel extends Events.EventEmitter { public setFocus(element?: any, eventPayload?: any): void { this.setTraits('focused', element ? [element] : []); var eventData: _.IFocusEvent = { focus: this.getFocus(), payload: eventPayload }; - this.emit('focus', eventData); + this._onDidFocus.fire(eventData); } public isFocused(element: any): boolean { @@ -1415,6 +1539,23 @@ export class TreeModel extends Events.EventEmitter { this.registry = null; } - super.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/vs/base/parts/tree/browser/treeView.ts b/src/vs/base/parts/tree/browser/treeView.ts index 2aea91d703f..9a43ec43f17 100644 --- a/src/vs/base/parts/tree/browser/treeView.ts +++ b/src/vs/base/parts/tree/browser/treeView.ts @@ -23,7 +23,6 @@ import { HeightMap, IViewItem } from 'vs/base/parts/tree/browser/treeViewModel'; import _ = require('vs/base/parts/tree/browser/tree'); import { KeyCode } from 'vs/base/common/keyCodes'; import Event, { Emitter } from 'vs/base/common/event'; -import { EmitterEvent } from 'vs/base/common/eventEmitter'; export interface IRow { element: HTMLElement; @@ -715,65 +714,21 @@ export class TreeView extends HeightMap { this.releaseModel(); this.model = newModel; - this.modelListeners.push(this.model.addBulkListener((e) => this.onModelEvents(e))); - } - - private onModelEvents(events: EmitterEvent[]): void { - var elementsToRefresh: Model.Item[] = []; - - for (var i = 0, len = events.length; i < len; i++) { - var event = events[i]; - var data = event.data; - - switch (event.type) { - case 'refreshing': - this.onRefreshing(); - break; - case 'refreshed': - this.onRefreshed(); - break; - case 'clearingInput': - this.onClearingInput(data); - break; - case 'setInput': - this.onSetInput(data); - break; - case 'item:childrenRefreshing': - this.onItemChildrenRefreshing(data); - break; - case 'item:childrenRefreshed': - this.onItemChildrenRefreshed(data); - break; - case 'item:refresh': - elementsToRefresh.push(data.item); - break; - case 'item:expanding': - this.onItemExpanding(data); - break; - case 'item:expanded': - this.onItemExpanded(data); - break; - case 'item:collapsing': - this.onItemCollapsing(data); - break; - case 'item:reveal': - this.onItemReveal(data); - break; - case 'item:addTrait': - this.onItemAddTrait(data); - break; - case 'item:removeTrait': - this.onItemRemoveTrait(data); - break; - case 'focus': - this.onModelFocusChange(); - break; - } - } + this.model.onRefresh(this.onRefreshing, this, this.modelListeners); + this.model.onDidRefresh(this.onRefreshed, this, this.modelListeners); + this.model.onSetInput(this.onClearingInput, this, this.modelListeners); + this.model.onDidSetInput(this.onSetInput, this, this.modelListeners); + this.model.onDidFocus(this.onModelFocusChange, this, this.modelListeners); - if (elementsToRefresh.length > 0) { - this.onItemsRefresh(elementsToRefresh); - } + this.model.onRefreshItemChildren(this.onItemChildrenRefreshing, this, this.modelListeners); + this.model.onDidRefreshItemChildren(this.onItemChildrenRefreshed, this, this.modelListeners); + this.model.onDidRefreshItem(this.onItemRefresh, this, this.modelListeners); + this.model.onExpandItem(this.onItemExpanding, this, this.modelListeners); + this.model.onDidExpandItem(this.onItemExpanded, this, this.modelListeners); + this.model.onCollapseItem(this.onItemCollapsing, this, this.modelListeners); + this.model.onDidRevealItem(this.onItemReveal, this, this.modelListeners); + this.model.onDidAddTraitItem(this.onItemAddTrait, this, this.modelListeners); + this.model.onDidRemoveTraitItem(this.onItemRemoveTrait, this, this.modelListeners); } private onRefreshing(): void { @@ -1002,6 +957,10 @@ export class TreeView extends HeightMap { } } + private onItemRefresh(item: Model.Item): void { + this.onItemsRefresh([item]); + } + private onItemsRefresh(items: Model.Item[]): void { this.onRefreshItemSet(items.filter(item => this.items.hasOwnProperty(item.id))); this.onRowsChanged(); diff --git a/src/vs/base/parts/tree/test/browser/treeModel.test.ts b/src/vs/base/parts/tree/test/browser/treeModel.test.ts index e6bdfae1691..1e0dac447a2 100644 --- a/src/vs/base/parts/tree/test/browser/treeModel.test.ts +++ b/src/vs/base/parts/tree/test/browser/treeModel.test.ts @@ -9,9 +9,9 @@ import assert = require('assert'); import lifecycle = require('vs/base/common/lifecycle'); import _ = require('vs/base/parts/tree/browser/tree'); import WinJS = require('vs/base/common/winjs.base'); -import Events = require('vs/base/common/eventEmitter'); import model = require('vs/base/parts/tree/browser/treeModel'); import TreeDefaults = require('vs/base/parts/tree/browser/treeDefaults'); +import Event, { Emitter } from 'vs/base/common/event'; export class FakeRenderer { @@ -74,11 +74,11 @@ class EventCounter { this._count = 0; } - public listen(emitter: Events.IEventEmitter, event: string, fn: (e) => void = null): () => void { - let r = emitter.addListener(event, (e) => { + public listen<T>(event: Event<T>, fn: (e: T) => void = null): () => void { + let r = event(data => { this._count++; if (fn) { - fn(e); + fn(data); } }); @@ -203,11 +203,11 @@ suite('TreeModel', () => { test('refresh() refreshes all', (done) => { model.setInput(SAMPLE.AB).then(() => { - counter.listen(model, 'refreshing'); // 1 - counter.listen(model, 'refreshed'); // 1 - counter.listen(model, 'item:refresh'); // 4 - counter.listen(model, 'item:childrenRefreshing'); // 1 - counter.listen(model, 'item:childrenRefreshed'); // 1 + counter.listen(model.onRefresh); // 1 + counter.listen(model.onDidRefresh); // 1 + counter.listen(model.onDidRefreshItem); // 4 + counter.listen(model.onRefreshItemChildren); // 1 + counter.listen(model.onDidRefreshItemChildren); // 1 return model.refresh(null); }).done(() => { assert.equal(counter.count, 8); @@ -217,11 +217,11 @@ suite('TreeModel', () => { test('refresh(root) refreshes all', (done) => { model.setInput(SAMPLE.AB).then(() => { - counter.listen(model, 'refreshing'); // 1 - counter.listen(model, 'refreshed'); // 1 - counter.listen(model, 'item:refresh'); // 4 - counter.listen(model, 'item:childrenRefreshing'); // 1 - counter.listen(model, 'item:childrenRefreshed'); // 1 + counter.listen(model.onRefresh); // 1 + counter.listen(model.onDidRefresh); // 1 + counter.listen(model.onDidRefreshItem); // 4 + counter.listen(model.onRefreshItemChildren); // 1 + counter.listen(model.onDidRefreshItemChildren); // 1 return model.refresh(SAMPLE.AB); }).done(() => { assert.equal(counter.count, 8); @@ -231,11 +231,11 @@ suite('TreeModel', () => { test('refresh(root, false) refreshes the root', (done) => { model.setInput(SAMPLE.AB).then(() => { - counter.listen(model, 'refreshing'); // 1 - counter.listen(model, 'refreshed'); // 1 - counter.listen(model, 'item:refresh'); // 1 - counter.listen(model, 'item:childrenRefreshing'); // 1 - counter.listen(model, 'item:childrenRefreshed'); // 1 + counter.listen(model.onRefresh); // 1 + counter.listen(model.onDidRefresh); // 1 + counter.listen(model.onDidRefreshItem); // 1 + counter.listen(model.onRefreshItemChildren); // 1 + counter.listen(model.onDidRefreshItemChildren); // 1 return model.refresh(SAMPLE.AB, false); }).done(() => { assert.equal(counter.count, 5); @@ -245,11 +245,11 @@ suite('TreeModel', () => { test('refresh(collapsed element) does not refresh descendants', (done) => { model.setInput(SAMPLE.AB).then(() => { - counter.listen(model, 'refreshing'); // 1 - counter.listen(model, 'refreshed'); // 1 - counter.listen(model, 'item:refresh'); // 1 - counter.listen(model, 'item:childrenRefreshing'); // 0 - counter.listen(model, 'item:childrenRefreshed'); // 0 + counter.listen(model.onRefresh); // 1 + counter.listen(model.onDidRefresh); // 1 + counter.listen(model.onDidRefreshItem); // 1 + counter.listen(model.onRefreshItemChildren); // 0 + counter.listen(model.onDidRefreshItemChildren); // 0 return model.refresh(SAMPLE.AB.children[0]); }).done(() => { assert.equal(counter.count, 3); @@ -261,11 +261,11 @@ suite('TreeModel', () => { model.setInput(SAMPLE.AB).then(() => { model.expand(SAMPLE.AB.children[0]); - counter.listen(model, 'refreshing'); // 1 - counter.listen(model, 'refreshed'); // 1 - counter.listen(model, 'item:refresh'); // 3 - counter.listen(model, 'item:childrenRefreshing'); // 1 - counter.listen(model, 'item:childrenRefreshed'); // 1 + counter.listen(model.onRefresh); // 1 + counter.listen(model.onDidRefresh); // 1 + counter.listen(model.onDidRefreshItem); // 3 + counter.listen(model.onRefreshItemChildren); // 1 + counter.listen(model.onDidRefreshItemChildren); // 1 return model.refresh(SAMPLE.AB.children[0]); }).done(() => { assert.equal(counter.count, 7); @@ -277,14 +277,14 @@ suite('TreeModel', () => { model.setInput(SAMPLE.AB).then(() => { model.expand(SAMPLE.AB.children[0]); - counter.listen(model, 'refreshing'); // 1 - counter.listen(model, 'refreshed'); // 1 - counter.listen(model, 'item:refresh', (e) => { // 1 - assert.equal(e.item.id, 'a'); + counter.listen(model.onRefresh); // 1 + counter.listen(model.onDidRefresh); // 1 + counter.listen(model.onDidRefreshItem, item => { // 1 + assert.equal(item.id, 'a'); counter.up(); }); - counter.listen(model, 'item:childrenRefreshing'); // 1 - counter.listen(model, 'item:childrenRefreshed'); // 1 + counter.listen(model.onRefreshItemChildren); // 1 + counter.listen(model.onDidRefreshItemChildren); // 1 return model.refresh(SAMPLE.AB.children[0], false); }).done(() => { assert.equal(counter.count, 6); @@ -296,16 +296,16 @@ suite('TreeModel', () => { model.setInput(SAMPLE.AB).then(() => { model.expandAll(['a', 'c']); - counter.listen(model, 'item:refresh', (e) => { - switch (e.item.id) { - case 'ROOT': assert.equal(e.item.getDepth(), 0); break; - case 'a': assert.equal(e.item.getDepth(), 1); break; - case 'aa': assert.equal(e.item.getDepth(), 2); break; - case 'ab': assert.equal(e.item.getDepth(), 2); break; - case 'b': assert.equal(e.item.getDepth(), 1); break; - case 'c': assert.equal(e.item.getDepth(), 1); break; - case 'ca': assert.equal(e.item.getDepth(), 2); break; - case 'cb': assert.equal(e.item.getDepth(), 2); break; + counter.listen(model.onDidRefreshItem, item => { + switch (item.id) { + case 'ROOT': assert.equal(item.getDepth(), 0); break; + case 'a': assert.equal(item.getDepth(), 1); break; + case 'aa': assert.equal(item.getDepth(), 2); break; + case 'ab': assert.equal(item.getDepth(), 2); break; + case 'b': assert.equal(item.getDepth(), 1); break; + case 'c': assert.equal(item.getDepth(), 1); break; + case 'ca': assert.equal(item.getDepth(), 2); break; + case 'cb': assert.equal(item.getDepth(), 2); break; default: return; } counter.up(); @@ -548,13 +548,13 @@ suite('TreeModel - Expansion', () => { test('collapse, expand', (done) => { model.setInput(SAMPLE.AB).done(() => { - counter.listen(model, 'item:expanding', (e) => { + counter.listen(model.onExpandItem, (e) => { assert.equal(e.item.id, 'a'); var nav = model.getNavigator(e.item); assert.equal(nav.next() && false, null); }); - counter.listen(model, 'item:expanded', (e) => { + counter.listen(model.onDidExpandItem, (e) => { assert.equal(e.item.id, 'a'); var nav = model.getNavigator(e.item); assert.equal(nav.next().id, 'aa'); @@ -675,12 +675,12 @@ suite('TreeModel - Expansion', () => { assert.equal(nav.next().id, 'c'); assert.equal(nav.next() && false, null); - var f: () => void = counter.listen(model, 'item:childrenRefreshing', (e) => { + var f: () => void = counter.listen(model.onRefreshItemChildren, (e) => { assert.equal(e.item.id, 'a'); f(); }); - var g: () => void = counter.listen(model, 'item:childrenRefreshed', (e) => { + var g: () => void = counter.listen(model.onDidRefreshItemChildren, (e) => { assert.equal(e.item.id, 'a'); g(); }); @@ -1138,13 +1138,18 @@ suite('TreeModel - Traits', () => { }); }); -class DynamicModel extends Events.EventEmitter implements _.IDataSource { +class DynamicModel implements _.IDataSource { private data: any; public promiseFactory: { (): WinJS.Promise; }; + private _onGetChildren = new Emitter<any>(); + readonly onGetChildren: Event<any> = this._onGetChildren.event; + + private _onDidGetChildren = new Emitter<any>(); + readonly onDidGetChildren: Event<any> = this._onDidGetChildren.event; + constructor() { - super(); this.data = { root: [] }; this.promiseFactory = null; } @@ -1182,10 +1187,10 @@ class DynamicModel extends Events.EventEmitter implements _.IDataSource { } public getChildren(tree, element): WinJS.Promise { - this.emit('getChildren', element); + this._onGetChildren.fire(element); var result = this.promiseFactory ? this.promiseFactory() : WinJS.TPromise.as(null); return result.then(() => { - this.emit('gotChildren', element); + this._onDidGetChildren.fire(element); return WinJS.TPromise.as(this.data[element]); }); } @@ -1226,8 +1231,8 @@ suite('TreeModel - Dynamic data model', () => { var items = ['baby', 'son', 'daughter', 'father']; var times = 0; - counter.listen(model, 'item:dispose', (e) => { - assert.equal(items[times++], e.item.id); + counter.listen(model.onDidDisposeItem, item => { + assert.equal(items[times++], item.id); }); model.refresh().done(() => { @@ -1338,7 +1343,7 @@ suite('TreeModel - Dynamic data model', () => { model.collapse('father'); var times = 0; - var listener = dataModel.addListener('getChildren', (element) => { + var listener = dataModel.onGetChildren((element) => { times++; assert.equal(element, 'grandfather'); }); @@ -1347,7 +1352,7 @@ suite('TreeModel - Dynamic data model', () => { assert.equal(times, 1); listener.dispose(); - listener = dataModel.addListener('getChildren', (element) => { + listener = dataModel.onGetChildren((element) => { times++; assert.equal(element, 'father'); }); @@ -1387,8 +1392,8 @@ suite('TreeModel - Dynamic data model', () => { var getTimes = 0; var gotTimes = 0; - var getListener = dataModel.addListener('getChildren', (element) => { getTimes++; }); - var gotListener = dataModel.addListener('gotChildren', (element) => { gotTimes++; }); + var getListener = dataModel.onGetChildren((element) => { getTimes++; }); + var gotListener = dataModel.onDidGetChildren((element) => { gotTimes++; }); var p1 = model.refresh('father'); assert.equal(getTimes, 1); @@ -1432,13 +1437,13 @@ suite('TreeModel - Dynamic data model', () => { assert.equal(nav.next() && false, null); var refreshTimes = 0; - counter.listen(model, 'item:refresh', (e) => { refreshTimes++; }); + counter.listen(model.onDidRefreshItem, (e) => { refreshTimes++; }); var getTimes = 0; - var getListener = dataModel.addListener('getChildren', (element) => { getTimes++; }); + var getListener = dataModel.onGetChildren((element) => { getTimes++; }); var gotTimes = 0; - var gotListener = dataModel.addListener('gotChildren', (element) => { gotTimes++; }); + var gotListener = dataModel.onDidGetChildren((element) => { gotTimes++; }); var p1Completes = []; dataModel.promiseFactory = () => { return new WinJS.TPromise((c) => { p1Completes.push(c); }); }; @@ -1513,8 +1518,8 @@ suite('TreeModel - Dynamic data model', () => { var getTimes = 0; var gotTimes = 0; - var getListener = dataModel.addListener('getChildren', (element) => { getTimes++; }); - var gotListener = dataModel.addListener('gotChildren', (element) => { gotTimes++; }); + var getListener = dataModel.onGetChildren((element) => { getTimes++; }); + var gotListener = dataModel.onDidGetChildren((element) => { gotTimes++; }); var p2; var p1Complete; @@ -1710,8 +1715,8 @@ suite('TreeModel - bugs', () => { var getBartChildren = getGetBartChildren(0); // item expanding should not exist! - counter.listen(model, 'item:expanding', () => { assert(false, 'should never receive item:expanding event'); }); - counter.listen(model, 'item:expanded', () => { assert(false, 'should never receive item:expanded event'); }); + counter.listen(model.onExpandItem, () => { assert(false, 'should never receive item:expanding event'); }); + counter.listen(model.onDidExpandItem, () => { assert(false, 'should never receive item:expanded event'); }); model.setInput('root').then(() => { diff --git a/src/vs/editor/contrib/referenceSearch/referencesWidget.ts b/src/vs/editor/contrib/referenceSearch/referencesWidget.ts index c2f1e03e6f4..a59115af0b6 100644 --- a/src/vs/editor/contrib/referenceSearch/referencesWidget.ts +++ b/src/vs/editor/contrib/referenceSearch/referencesWidget.ts @@ -218,11 +218,14 @@ class DataSource implements tree.IDataSource { class Controller extends DefaultController { - static Events = { - FOCUSED: 'events/custom/focused', - SELECTED: 'events/custom/selected', - OPEN_TO_SIDE: 'events/custom/opentoside' - }; + private _onDidFocus = new Emitter<any>(); + readonly onDidFocus: Event<any> = this._onDidFocus.event; + + private _onDidSelect = new Emitter<any>(); + readonly onDidSelect: Event<any> = this._onDidSelect.event; + + private _onDidOpenToSide = new Emitter<any>(); + readonly onDidOpenToSide: Event<any> = this._onDidOpenToSide.event; public onTap(tree: tree.ITree, element: any, event: GestureEvent): boolean { if (element instanceof FileReferences) { @@ -232,7 +235,8 @@ class Controller extends DefaultController { } var result = super.onTap(tree, element, event); - tree.emit(Controller.Events.FOCUSED, element); + + this._onDidFocus.fire(element); return result; } @@ -246,11 +250,11 @@ class Controller extends DefaultController { var result = super.onClick(tree, element, event); if (event.ctrlKey || event.metaKey) { - tree.emit(Controller.Events.OPEN_TO_SIDE, element); + this._onDidOpenToSide.fire(element); } else if (event.detail === 2) { - tree.emit(Controller.Events.SELECTED, element); + this._onDidSelect.fire(element); } else { - tree.emit(Controller.Events.FOCUSED, element); + this._onDidFocus.fire(element); } return result; } @@ -288,9 +292,9 @@ class Controller extends DefaultController { var result = super.onEnter(tree, event); if (event.ctrlKey || event.metaKey) { - tree.emit(Controller.Events.OPEN_TO_SIDE, element); + this._onDidOpenToSide.fire(element); } else { - tree.emit(Controller.Events.SELECTED, element); + this._onDidSelect.fire(element); } return result; } @@ -336,7 +340,13 @@ class Controller extends DefaultController { var focus = tree.getFocus(); tree.setSelection([focus]); // send out event - tree.emit(Controller.Events.FOCUSED, focus); + this._onDidFocus.fire(focus); + } + + dispose(): void { + this._onDidFocus.dispose(); + this._onDidSelect.dispose(); + this._onDidOpenToSide.dispose(); } } @@ -676,13 +686,33 @@ export class ReferenceWidget extends PeekViewWidget { // tree container.div({ 'class': 'ref-tree inline' }, (div: Builder) => { + const controller = new Controller(); var config = <tree.ITreeConfiguration>{ dataSource: this._instantiationService.createInstance(DataSource), renderer: this._instantiationService.createInstance(Renderer), - controller: new Controller(), + controller, accessibilityProvider: new AriaProvider() }; + // listen on selection and focus + this._disposables.push(controller.onDidFocus((element) => { + if (element instanceof OneReference) { + this._revealReference(element); + this._onDidSelectReference.fire({ element, kind: 'show', source: 'tree' }); + } + })); + + this._disposables.push(controller.onDidSelect((element: any) => { + if (element instanceof OneReference) { + this._onDidSelectReference.fire({ element, kind: 'goto', source: 'tree' }); + } + })); + this._disposables.push(controller.onDidOpenToSide((element: any) => { + if (element instanceof OneReference) { + this._onDidSelectReference.fire({ element, kind: 'side', source: 'tree' }); + } + })); + var options = { allowHorizontalScroll: false, twistiePixels: 20, @@ -752,25 +782,6 @@ export class ReferenceWidget extends PeekViewWidget { // listen on model changes this._disposeOnNewModel.push(this._model.onDidChangeReferenceRange(reference => this._tree.refresh(reference))); - // listen on selection and focus - this._disposeOnNewModel.push(this._tree.addListener(Controller.Events.FOCUSED, (element) => { - if (element instanceof OneReference) { - this._revealReference(element); - this._onDidSelectReference.fire({ element, kind: 'show', source: 'tree' }); - } - })); - - this._disposeOnNewModel.push(this._tree.addListener(Controller.Events.SELECTED, (element: any) => { - if (element instanceof OneReference) { - this._onDidSelectReference.fire({ element, kind: 'goto', source: 'tree' }); - } - })); - this._disposeOnNewModel.push(this._tree.addListener(Controller.Events.OPEN_TO_SIDE, (element: any) => { - if (element instanceof OneReference) { - this._onDidSelectReference.fire({ element, kind: 'side', source: 'tree' }); - } - })); - // listen on editor this._disposeOnNewModel.push(this._preview.onMouseDown((e) => { if (e.event.detail === 2) { diff --git a/src/vs/platform/list/browser/listService.ts b/src/vs/platform/list/browser/listService.ts index bf6575077b5..6c91a4518ec 100644 --- a/src/vs/platform/list/browser/listService.ts +++ b/src/vs/platform/list/browser/listService.ts @@ -76,15 +76,15 @@ export class ListService implements IListService { } const toDispose = [ - widget.onDOMFocus(() => this.focusChangeScheduler.schedule()), - widget.onDOMBlur(() => this.focusChangeScheduler.schedule()) + widget.onDidFocus(() => this.focusChangeScheduler.schedule()), + widget.onDidBlur(() => this.focusChangeScheduler.schedule()) ]; // Special treatment for tree highlight mode if (!(widget instanceof List)) { const tree = widget; - toDispose.push(tree.onHighlightChange(() => { + toDispose.push(tree.onDidChangeHighlight(() => { this.focusChangeScheduler.schedule(); })); } diff --git a/src/vs/workbench/browser/parts/views/treeView.ts b/src/vs/workbench/browser/parts/views/treeView.ts index ba88ed44156..30d2e6856e2 100644 --- a/src/vs/workbench/browser/parts/views/treeView.ts +++ b/src/vs/workbench/browser/parts/views/treeView.ts @@ -100,7 +100,7 @@ export class TreeView extends ViewsViewletPanel { this.disposables.push(attachListStyler(tree, this.themeService)); this.disposables.push(this.listService.register(tree, [this.viewFocusContext])); - tree.addListener('selection', (event: any) => this.onSelection()); + this.disposables.push(tree.onDidChangeSelection(() => this.onSelection())); return tree; } diff --git a/src/vs/workbench/parts/debug/electron-browser/debugHover.ts b/src/vs/workbench/parts/debug/electron-browser/debugHover.ts index 9dec498f49a..3dd805e96a0 100644 --- a/src/vs/workbench/parts/debug/electron-browser/debugHover.ts +++ b/src/vs/workbench/parts/debug/electron-browser/debugHover.ts @@ -105,10 +105,10 @@ export class DebugHoverWidget implements IContentWidget { } private registerListeners(): void { - this.toDispose.push(this.tree.addListener('item:expanded', () => { + this.toDispose.push(this.tree.onDidExpandItem(() => { this.layoutTree(); })); - this.toDispose.push(this.tree.addListener('item:collapsed', () => { + this.toDispose.push(this.tree.onDidCollapseItem(() => { this.layoutTree(); })); diff --git a/src/vs/workbench/parts/debug/electron-browser/debugViewer.ts b/src/vs/workbench/parts/debug/electron-browser/debugViewer.ts index e3e0580f11a..6ceb6e94793 100644 --- a/src/vs/workbench/parts/debug/electron-browser/debugViewer.ts +++ b/src/vs/workbench/parts/debug/electron-browser/debugViewer.ts @@ -299,7 +299,7 @@ export class CallStackController extends BaseDebugController { return true; } - public focusStackFrame(stackFrame: debug.IStackFrame, event: IKeyboardEvent | IMouseEvent, preserveFocus: boolean): void { + public focusStackFrame(stackFrame: debug.IStackFrame, event: any, preserveFocus: boolean): void { this.debugService.focusStackFrameAndEvaluate(stackFrame, undefined, true).then(() => { const sideBySide = (event && (event.ctrlKey || event.metaKey)); return stackFrame.openInEditor(this.editorService, preserveFocus, sideBySide); @@ -1290,7 +1290,7 @@ export class BreakpointsController extends BaseDebugController { return super.onLeftClick(tree, element, event); } - public openBreakpointSource(breakpoint: Breakpoint, event: IKeyboardEvent | IMouseEvent, preserveFocus: boolean): void { + public openBreakpointSource(breakpoint: Breakpoint, event: any, preserveFocus: boolean): void { if (breakpoint.uri.scheme === debug.DEBUG_SCHEME && this.debugService.state === debug.State.Inactive) { return; } diff --git a/src/vs/workbench/parts/debug/electron-browser/debugViews.ts b/src/vs/workbench/parts/debug/electron-browser/debugViews.ts index 77c31005f1c..b2324b2b712 100644 --- a/src/vs/workbench/parts/debug/electron-browser/debugViews.ts +++ b/src/vs/workbench/parts/debug/electron-browser/debugViews.ts @@ -10,7 +10,6 @@ import * as dom from 'vs/base/browser/dom'; import * as builder from 'vs/base/browser/builder'; import { TPromise } from 'vs/base/common/winjs.base'; import * as errors from 'vs/base/common/errors'; -import { EventType } from 'vs/base/common/events'; import { IAction } from 'vs/base/common/actions'; import { prepareActions } from 'vs/workbench/browser/actions'; import { IHighlightEvent, ITree } from 'vs/base/parts/tree/browser/tree'; @@ -29,6 +28,7 @@ import { IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/c import { IListService } from 'vs/platform/list/browser/listService'; import { attachListStyler } from 'vs/platform/theme/common/styler'; import { IThemeService } from 'vs/platform/theme/common/themeService'; +import { once } from 'vs/base/common/event'; function renderViewTree(container: HTMLElement): HTMLElement { const treeContainer = document.createElement('div'); @@ -136,7 +136,7 @@ export class VariablesView extends ViewsViewletPanel { this.tree.refresh(expression, false).then(() => { this.tree.setHighlight(expression); - this.tree.addOneTimeListener(EventType.HIGHLIGHT, (e: IHighlightEvent) => { + once(this.tree.onDidChangeHighlight)((e: IHighlightEvent) => { if (!e.highlight) { this.debugService.getViewModel().setSelectedExpression(null); } @@ -228,7 +228,7 @@ export class WatchExpressionsView extends ViewsViewletPanel { this.tree.refresh(expression, false).then(() => { this.tree.setHighlight(expression); - this.tree.addOneTimeListener(EventType.HIGHLIGHT, (e: IHighlightEvent) => { + once(this.tree.onDidChangeHighlight)((e: IHighlightEvent) => { if (!e.highlight) { this.debugService.getViewModel().setSelectedExpression(null); } @@ -319,7 +319,7 @@ export class CallStackView extends ViewsViewletPanel { this.disposables.push(attachListStyler(this.tree, this.themeService)); this.disposables.push(this.listService.register(this.tree)); - this.disposables.push(this.tree.addListener('selection', event => { + this.disposables.push(this.tree.onDidChangeSelection(event => { if (event && event.payload && event.payload.origin === 'keyboard') { const element = this.tree.getFocus(); if (element instanceof ThreadAndProcessIds) { @@ -454,7 +454,7 @@ export class BreakpointsView extends ViewsViewletPanel { this.disposables.push(attachListStyler(this.tree, this.themeService)); this.disposables.push(this.listService.register(this.tree, [this.breakpointsFocusedContext])); - this.disposables.push(this.tree.addListener('selection', event => { + this.disposables.push(this.tree.onDidChangeSelection(event => { if (event && event.payload && event.payload.origin === 'keyboard') { const element = this.tree.getFocus(); if (element instanceof Breakpoint) { @@ -474,7 +474,7 @@ export class BreakpointsView extends ViewsViewletPanel { this.tree.refresh(fbp, false).then(() => { this.tree.setHighlight(fbp); - this.tree.addOneTimeListener(EventType.HIGHLIGHT, (e: IHighlightEvent) => { + once(this.tree.onDidChangeHighlight)((e: IHighlightEvent) => { if (!e.highlight) { this.debugService.getViewModel().setSelectedFunctionBreakpoint(null); } diff --git a/src/vs/workbench/parts/extensions/browser/extensionEditor.ts b/src/vs/workbench/parts/extensions/browser/extensionEditor.ts index 5489c928ecf..d2102082d06 100644 --- a/src/vs/workbench/parts/extensions/browser/extensionEditor.ts +++ b/src/vs/workbench/parts/extensions/browser/extensionEditor.ts @@ -532,7 +532,7 @@ export class ExtensionEditor extends BaseEditor { tree.setInput(extensionDependencies); - this.contentDisposables.push(tree.addListener('selection', event => { + this.contentDisposables.push(tree.onDidChangeSelection(event => { if (event && event.payload && event.payload.origin === 'keyboard') { controller.openExtension(tree, false); } diff --git a/src/vs/workbench/parts/files/browser/fileActions.ts b/src/vs/workbench/parts/files/browser/fileActions.ts index 864e141fa9c..fdb24e9ea11 100644 --- a/src/vs/workbench/parts/files/browser/fileActions.ts +++ b/src/vs/workbench/parts/files/browser/fileActions.ts @@ -16,7 +16,6 @@ import URI from 'vs/base/common/uri'; import errors = require('vs/base/common/errors'); import { toErrorMessage } from 'vs/base/common/errorMessage'; import strings = require('vs/base/common/strings'); -import { EventType as CommonEventType } from 'vs/base/common/events'; import severity from 'vs/base/common/severity'; import diagnostics = require('vs/base/common/diagnostics'); import { Action, IAction } from 'vs/base/common/actions'; @@ -209,7 +208,7 @@ export class TriggerRenameFileAction extends BaseFileAction { this.tree.refresh(stat, false).then(() => { this.tree.setHighlight(stat); - const unbind = this.tree.addListener(CommonEventType.HIGHLIGHT, (e: IHighlightEvent) => { + const unbind = this.tree.onDidChangeHighlight((e: IHighlightEvent) => { if (!e.highlight) { viewletState.clearEditable(stat); this.tree.refresh(stat).done(null, errors.onUnexpectedError); @@ -422,7 +421,7 @@ export class BaseNewAction extends BaseFileAction { return this.tree.reveal(stat, 0.5).then(() => { this.tree.setHighlight(stat); - const unbind = this.tree.addListener(CommonEventType.HIGHLIGHT, (e: IHighlightEvent) => { + const unbind = this.tree.onDidChangeHighlight((e: IHighlightEvent) => { if (!e.highlight) { stat.destroy(); this.tree.refresh(folder).done(null, errors.onUnexpectedError); diff --git a/src/vs/workbench/parts/files/browser/fileResultsNavigation.ts b/src/vs/workbench/parts/files/browser/fileResultsNavigation.ts index 9174477d966..79f3a7ca198 100644 --- a/src/vs/workbench/parts/files/browser/fileResultsNavigation.ts +++ b/src/vs/workbench/parts/files/browser/fileResultsNavigation.ts @@ -22,8 +22,8 @@ export default class FileResultsNavigation extends Disposable { constructor(private tree: ITree) { super(); - this._register(this.tree.addListener('focus', e => this.onFocus(e))); - this._register(this.tree.addListener('selection', e => this.onSelection(e))); + this._register(this.tree.onDidChangeFocus(e => this.onFocus(e))); + this._register(this.tree.onDidChangeSelection(e => this.onSelection(e))); } private onFocus(event: any): void { diff --git a/src/vs/workbench/parts/files/browser/views/explorerView.ts b/src/vs/workbench/parts/files/browser/views/explorerView.ts index aa58908d1e4..8c0bb21d272 100644 --- a/src/vs/workbench/parts/files/browser/views/explorerView.ts +++ b/src/vs/workbench/parts/files/browser/views/explorerView.ts @@ -443,13 +443,13 @@ export class ExplorerView extends ViewsViewletPanel { this.disposables.push(this.fileService.onFileChanges(e => this.onFileChanges(e))); // Update resource context based on focused element - this.disposables.push(this.explorerViewer.addListener('focus', (e: { focus: FileStat }) => { + this.disposables.push(this.explorerViewer.onDidChangeFocus((e: { focus: FileStat }) => { this.resourceContext.set(e.focus && e.focus.resource); this.folderContext.set(e.focus && e.focus.isDirectory); })); // Open when selecting via keyboard - this.disposables.push(this.explorerViewer.addListener('selection', event => { + this.disposables.push(this.explorerViewer.onDidChangeSelection(event => { if (event && event.payload && event.payload.origin === 'keyboard') { const element = this.tree.getSelection(); diff --git a/src/vs/workbench/parts/files/browser/views/openEditorsView.ts b/src/vs/workbench/parts/files/browser/views/openEditorsView.ts index e248d36c195..6467e58b843 100644 --- a/src/vs/workbench/parts/files/browser/views/openEditorsView.ts +++ b/src/vs/workbench/parts/files/browser/views/openEditorsView.ts @@ -145,14 +145,14 @@ export class OpenEditorsView extends ViewsViewletPanel { this.disposables.push(this.listService.register(this.tree, [this.explorerFocusedContext, this.openEditorsFocusedContext])); // Open when selecting via keyboard - this.disposables.push(this.tree.addListener('selection', event => { + this.disposables.push(this.tree.onDidChangeSelection(event => { if (event && event.payload && event.payload.origin === 'keyboard') { controller.openEditor(this.tree.getFocus(), { pinned: false, sideBySide: false, preserveFocus: false }); } })); // Prevent collapsing of editor groups - this.disposables.push(this.tree.addListener('item:collapsed', (event: IItemCollapseEvent) => { + this.disposables.push(this.tree.onDidCollapseItem((event: IItemCollapseEvent) => { if (event.item && event.item.getElement() instanceof EditorGroup) { setTimeout(() => this.tree.expand(event.item.getElement())); // unwind from callback } diff --git a/src/vs/workbench/parts/markers/browser/markersPanel.ts b/src/vs/workbench/parts/markers/browser/markersPanel.ts index 7896ae60685..17d1e7cc94f 100644 --- a/src/vs/workbench/parts/markers/browser/markersPanel.ts +++ b/src/vs/workbench/parts/markers/browser/markersPanel.ts @@ -217,7 +217,7 @@ export class MarkersPanel extends Panel { this._register(attachListStyler(this.tree, this.themeService)); - this._register(this.tree.addListener('focus', (e: { focus: any }) => { + this._register(this.tree.onDidChangeFocus((e: { focus: any }) => { this.markerFocusContextKey.set(e.focus instanceof Marker); })); @@ -249,7 +249,7 @@ export class MarkersPanel extends Panel { private createListeners(): void { this.toUnbind.push(this.markerService.onMarkerChanged(this.onMarkerChanged, this)); this.toUnbind.push(this.editorGroupService.onEditorsChanged(this.onEditorsChanged, this)); - this.toUnbind.push(this.tree.addListener('selection', () => this.onSelected())); + this.toUnbind.push(this.tree.onDidChangeSelection(() => this.onSelected())); } private onMarkerChanged(changedResources: URI[]) { diff --git a/src/vs/workbench/parts/preferences/browser/keybindingsEditor.ts b/src/vs/workbench/parts/preferences/browser/keybindingsEditor.ts index 18e5249494b..d05141ecc03 100644 --- a/src/vs/workbench/parts/preferences/browser/keybindingsEditor.ts +++ b/src/vs/workbench/parts/preferences/browser/keybindingsEditor.ts @@ -332,10 +332,10 @@ export class KeybindingsEditor extends BaseEditor implements IKeybindingsEditor { identityProvider: e => e.id, keyboardSupport: false, mouseSupport: true, ariaLabel: localize('keybindingsLabel', "Keybindings") })); this._register(this.keybindingsList.onContextMenu(e => this.onContextMenu(e))); this._register(this.keybindingsList.onFocusChange(e => this.onFocusChange(e))); - this._register(this.keybindingsList.onDOMFocus(() => { + this._register(this.keybindingsList.onDidFocus(() => { DOM.addClass(this.keybindingsList.getHTMLElement(), 'focused'); })); - this._register(this.keybindingsList.onDOMBlur(() => { + this._register(this.keybindingsList.onDidBlur(() => { DOM.removeClass(this.keybindingsList.getHTMLElement(), 'focused'); this.keybindingFocusContextKey.reset(); })); diff --git a/src/vs/workbench/parts/search/browser/searchViewlet.ts b/src/vs/workbench/parts/search/browser/searchViewlet.ts index 48fd64b555f..05c2a2c4389 100644 --- a/src/vs/workbench/parts/search/browser/searchViewlet.ts +++ b/src/vs/workbench/parts/search/browser/searchViewlet.ts @@ -524,7 +524,7 @@ export class SearchViewlet extends Viewlet { } })); - this.toUnbind.push(this.tree.addListener('focus', (e: IFocusEvent) => { + this.toUnbind.push(this.tree.onDidChangeFocus((e: IFocusEvent) => { const focus = e.focus; this.firstMatchFocused.set(this.tree.getNavigator().first() === focus); this.fileMatchOrMatchFocused.set(true); @@ -533,7 +533,7 @@ export class SearchViewlet extends Viewlet { this.matchFocused.set(focus instanceof Match); })); - this.toUnbind.push(this.tree.onDOMBlur(e => { + this.toUnbind.push(this.tree.onDidBlur(e => { this.firstMatchFocused.reset(); this.fileMatchOrMatchFocused.reset(); this.fileMatchFocused.reset(); |