提交 4f35ddd2 编写于 作者: B Benjamin Pasero

get rid of EventEmitter for editor inputs, models and workbench components

上级 ae95c243
......@@ -6,8 +6,8 @@
import URI from 'vs/base/common/uri';
import {TPromise} from 'vs/base/common/winjs.base';
import {IEventEmitter} from 'vs/base/common/eventEmitter';
import {createDecorator} from 'vs/platform/instantiation/common/instantiation';
import Event from 'vs/base/common/event';
export const IEditorService = createDecorator<IEditorService>('editorService');
......@@ -26,12 +26,17 @@ export interface IEditorService {
resolveEditorModel(input: IResourceInput, refresh?: boolean): TPromise<ITextEditorModel>;
}
export interface IEditorModel extends IEventEmitter {
export interface IEditorModel {
/**
* Loads the model.
*/
load(): TPromise<IEditorModel>;
/**
* Dispose associated resources
*/
dispose(): void;
}
export interface ITextEditorModel extends IEditorModel {
......@@ -125,7 +130,9 @@ export enum Direction {
RIGHT
}
export interface IEditorInput extends IEventEmitter {
export interface IEditorInput {
onDispose: Event<void>;
/**
* Returns the display name of this input.
......
......@@ -12,13 +12,7 @@ import {ITelemetryService} from 'vs/platform/telemetry/common/telemetry';
import {AsyncDescriptor} from 'vs/platform/instantiation/common/descriptors';
import {IComposite} from 'vs/workbench/common/composite';
import {IEditorControl} from 'vs/platform/editor/common/editor';
/**
* Internal composite events to communicate with composite container.
*/
export const EventType = {
INTERNAL_COMPOSITE_TITLE_AREA_UPDATE: 'internalCompositeTitleAreaUpdate'
};
import Event, {Emitter} from 'vs/base/common/event';
/**
* Composites are layed out in the sidebar and panel part of the workbench. At a time only one composite
......@@ -34,6 +28,7 @@ export abstract class Composite extends WorkbenchComponent implements IComposite
private _telemetryData: any = {};
private visible: boolean;
private parent: Builder;
private _onTitleAreaUpdate: Emitter<void>;
protected actionRunner: IActionRunner;
......@@ -44,6 +39,7 @@ export abstract class Composite extends WorkbenchComponent implements IComposite
super(id);
this.visible = false;
this._onTitleAreaUpdate = new Emitter<void>();
}
public getTitle(): string {
......@@ -58,6 +54,10 @@ export abstract class Composite extends WorkbenchComponent implements IComposite
return this._telemetryData;
}
public get onTitleAreaUpdate(): Event<void> {
return this._onTitleAreaUpdate.event;
}
/**
* Note: Clients should not call this method, the workbench calls this
* method. Calling it otherwise may result in unexpected behavior.
......@@ -179,7 +179,7 @@ export abstract class Composite extends WorkbenchComponent implements IComposite
* gets visible.
*/
protected updateTitleArea(): void {
this.emit(EventType.INTERNAL_COMPOSITE_TITLE_AREA_UPDATE, this.getId());
this._onTitleAreaUpdate.fire();
}
/**
......@@ -195,6 +195,12 @@ export abstract class Composite extends WorkbenchComponent implements IComposite
public getControl(): IEditorControl {
return null;
}
public dispose(): void {
this._onTitleAreaUpdate.dispose();
super.dispose();
}
}
/**
......
......@@ -24,7 +24,6 @@ import {Action, IAction} from 'vs/base/common/actions';
import {Part} from 'vs/workbench/browser/part';
import {Composite, CompositeRegistry} from 'vs/workbench/browser/composite';
import {IComposite} from 'vs/workbench/common/composite';
import {EventType as CompositeEventType} from 'vs/workbench/browser/composite';
import {WorkbenchProgressService} from 'vs/workbench/services/progress/browser/progressService';
import {IPartService} from 'vs/workbench/services/part/common/partService';
import {IStorageService, StorageScope} from 'vs/platform/storage/common/storage';
......@@ -182,7 +181,7 @@ export abstract class CompositePart<T extends Composite> extends Part {
this.instantiatedComposits.push(composite);
// Register to title area update events from the composite
this.instantiatedCompositeListeners.push(composite.addListener2(CompositeEventType.INTERNAL_COMPOSITE_TITLE_AREA_UPDATE, compositeId => this.onTitleAreaUpdate(compositeId)));
this.instantiatedCompositeListeners.push(composite.onTitleAreaUpdate(() => this.onTitleAreaUpdate(composite.getId())));
// Remove from Promises Cache since Loaded
delete this.compositeLoaderPromises[id];
......
......@@ -4,7 +4,6 @@
*--------------------------------------------------------------------------------------------*/
'use strict';
import {EventEmitter, IEventEmitter} from 'vs/base/common/eventEmitter';
import {IDisposable, dispose} from 'vs/base/common/lifecycle';
import {Scope, Memento} from 'vs/workbench/common/memento';
import {IStorageService} from 'vs/platform/storage/common/storage';
......@@ -14,7 +13,7 @@ import {IStorageService} from 'vs/platform/storage/common/storage';
* Provides some convinience methods to participate in the workbench lifecycle (dispose, shutdown) and
* loading and saving settings through memento.
*/
export interface IWorkbenchComponent extends IDisposable, IEventEmitter {
export interface IWorkbenchComponent extends IDisposable {
/**
* The unique identifier of this component.
......@@ -55,14 +54,12 @@ export interface IWorkbenchComponent extends IDisposable, IEventEmitter {
dispose(): void;
}
export class WorkbenchComponent extends EventEmitter implements IWorkbenchComponent {
export class WorkbenchComponent implements IWorkbenchComponent {
private _toUnbind: IDisposable[];
private id: string;
private componentMemento: Memento;
constructor(id: string) {
super();
this._toUnbind = [];
this.id = id;
this.componentMemento = new Memento(this.id);
......@@ -92,7 +89,5 @@ export class WorkbenchComponent extends EventEmitter implements IWorkbenchCompon
public dispose(): void {
this._toUnbind = dispose(this._toUnbind);
super.dispose();
}
}
\ No newline at end of file
......@@ -5,7 +5,6 @@
'use strict';
import {TPromise} from 'vs/base/common/winjs.base';
import {EventEmitter} from 'vs/base/common/eventEmitter';
import Event, {Emitter} from 'vs/base/common/event';
import types = require('vs/base/common/types');
import URI from 'vs/base/common/uri';
......@@ -120,16 +119,16 @@ export interface IEditorInputFactory {
* Editor inputs are lightweight objects that can be passed to the workbench API to open inside the editor part.
* Each editor input is mapped to an editor that is capable of opening it through the Platform facade.
*/
export abstract class EditorInput extends EventEmitter implements IEditorInput {
export abstract class EditorInput implements IEditorInput {
private _onDispose: Emitter<void>;
protected _onDidChangeDirty: Emitter<void>;
private disposed: boolean;
constructor() {
super();
this._onDidChangeDirty = new Emitter<void>();
this._onDispose = new Emitter<void>();
this.disposed = false;
}
......@@ -140,6 +139,13 @@ export abstract class EditorInput extends EventEmitter implements IEditorInput {
return this._onDidChangeDirty.event;
}
/**
* Fired when the model gets disposed.
*/
public get onDispose(): Event<void> {
return this._onDispose.event;
}
/**
* Returns the name of this input that can be shown to the user. Examples include showing the name of the input
* above the editor area when the input is shown.
......@@ -237,11 +243,11 @@ export abstract class EditorInput extends EventEmitter implements IEditorInput {
* resolving the editor input.
*/
public dispose(): void {
this._onDidChangeDirty.dispose();
this.disposed = true;
this.emit('dispose');
this._onDispose.fire();
super.dispose();
this._onDidChangeDirty.dispose();
this._onDispose.dispose();
}
/**
......@@ -399,7 +405,19 @@ export interface ITextEditorModel extends IEditorModel {
* connects to the disk to retrieve content and may allow for saving it back or reverting it. Editor models
* are typically cached for some while because they are expensive to construct.
*/
export class EditorModel extends EventEmitter implements IEditorModel {
export class EditorModel implements IEditorModel {
private _onDispose: Emitter<void>;
constructor() {
this._onDispose = new Emitter<void>();
}
/**
* Fired when the model gets disposed.
*/
public get onDispose(): Event<void> {
return this._onDispose.event;
}
/**
* Causes this model to load returning a promise when loading is completed.
......@@ -419,9 +437,8 @@ export class EditorModel extends EventEmitter implements IEditorModel {
* Subclasses should implement to free resources that have been claimed through loading.
*/
public dispose(): void {
this.emit('dispose');
super.dispose();
this._onDispose.fire();
this._onDispose.dispose();
}
}
......
......@@ -7,10 +7,10 @@
import nls = require('vs/nls');
import {TPromise} from 'vs/base/common/winjs.base';
import types = require('vs/base/common/types');
import {once} from 'vs/base/common/event';
import URI from 'vs/base/common/uri';
import {getPathLabel, IWorkspaceProvider} from 'vs/base/common/labels';
import {isBinaryMime} from 'vs/base/common/mime';
import {EventType} from 'vs/base/common/events';
import {EditorModel, IFileEditorInput, EditorInput, BaseDiffEditorInput} from 'vs/workbench/common/editor';
import {BaseTextEditorModel} from 'vs/workbench/common/editor/textEditorModel';
import {DiffEditorModel} from 'vs/workbench/common/editor/diffEditorModel';
......@@ -46,13 +46,15 @@ export class DiffEditorInput extends BaseDiffEditorInput {
private registerListeners(): void {
// When the original or modified input gets disposed, dispose this diff editor input
this._toUnbind.push(this.originalInput.addListener2(EventType.DISPOSE, () => {
const onceOriginalDisposed = once(this.originalInput.onDispose);
this._toUnbind.push(onceOriginalDisposed(() => {
if (!this.isDisposed()) {
this.dispose();
}
}));
this._toUnbind.push(this.modifiedInput.addListener2(EventType.DISPOSE, () => {
const onceModifiedDisposed = once(this.modifiedInput.onDispose);
this._toUnbind.push(onceModifiedDisposed(() => {
if (!this.isDisposed()) {
this.dispose();
}
......
......@@ -5,7 +5,7 @@
'use strict';
import Event, {Emitter} from 'vs/base/common/event';
import Event, {Emitter, once} from 'vs/base/common/event';
import {IEditorRegistry, Extensions, EditorInput, getUntitledOrFileResource, IEditorStacksModel, IEditorGroup, IEditorIdentifier, IGroupEvent, GroupIdentifier, IStacksModelChangeEvent, IWorkbenchEditorConfiguration, EditorOpenPositioning} from 'vs/workbench/common/editor';
import URI from 'vs/base/common/uri';
import {IStorageService, StorageScope} from 'vs/platform/storage/common/storage';
......@@ -296,7 +296,8 @@ export class EditorGroup implements IEditorGroup {
const unbind: IDisposable[] = [];
// Re-emit disposal of editor input as our own event
unbind.push(editor.addOneTimeDisposableListener('dispose', () => {
const onceDispose = once(editor.onDispose);
unbind.push(onceDispose(() => {
if (this.indexOf(editor) >= 0) {
this._onEditorDisposed.fire(editor);
}
......
......@@ -10,7 +10,6 @@ import {EditorModel, EditorInput} from 'vs/workbench/common/editor';
import {ResourceEditorModel} from 'vs/workbench/common/editor/resourceEditorModel';
import {IModel} from 'vs/editor/common/editorCommon';
import URI from 'vs/base/common/uri';
import {EventType} from 'vs/base/common/events';
import {IInstantiationService} from 'vs/platform/instantiation/common/instantiation';
import {IModelService} from 'vs/editor/common/services/modelService';
import {IDisposable} from 'vs/base/common/lifecycle';
......@@ -42,7 +41,7 @@ export class ResourceEditorInput extends EditorInput {
} else {
array.unshift(provider);
}
return {
dispose() {
let array = ResourceEditorInput.registry[scheme];
......@@ -158,7 +157,7 @@ export class ResourceEditorInput extends EditorInput {
// Otherwise Create Model and handle dispose event
return ResourceEditorInput.getOrCreateModel(this.modelService, this.resource).then(() => {
let model = this.instantiationService.createInstance(ResourceEditorModel, this.resource);
const unbind = model.addListener2(EventType.DISPOSE, () => {
const unbind = model.onDispose(() => {
this.cachedModel = null; // make sure we do not dispose model again
unbind.dispose();
this.dispose();
......
......@@ -23,7 +23,6 @@ import {IOptions} from 'vs/workbench/common/options';
import {IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions} from 'vs/workbench/common/contributions';
import {BaseEditor} from 'vs/workbench/browser/parts/editor/baseEditor';
import {IEditorRegistry, Extensions as EditorExtensions, TextEditorOptions, EditorInput, EditorOptions} from 'vs/workbench/common/editor';
import {Part} from 'vs/workbench/browser/part';
import {HistoryService} from 'vs/workbench/services/history/browser/history';
import {ActivitybarPart} from 'vs/workbench/browser/parts/activitybar/activitybarPart';
import {EditorPart} from 'vs/workbench/browser/parts/editor/editorPart';
......@@ -211,9 +210,6 @@ export class Workbench implements IPartService {
// Workbench Layout
this.createWorkbenchLayout();
// Register Emitters
this.registerEmitters();
// Load composits and editors in parallel
const compositeAndEditorPromises: TPromise<any>[] = [];
......@@ -649,19 +645,6 @@ export class Workbench implements IPartService {
this.toShutdown.forEach(s => s.shutdown());
}
private registerEmitters(): void {
// Part Emitters
this.hookPartListeners(this.activitybarPart);
this.hookPartListeners(this.editorPart);
this.hookPartListeners(this.sidebarPart);
this.hookPartListeners(this.panelPart);
}
private hookPartListeners(part: Part): void {
this.toDispose.push(this.eventService.addEmitter2(part, part.getId()));
}
private registerListeners(): void {
// Listen to editor changes
......
......@@ -192,7 +192,7 @@ export class TextFileEditorModelManager implements ITextFileEditorModelManager {
// store in cache but remove when model gets disposed
this.mapResourcePathToModel[resource.toString()] = model;
this.mapResourceToDisposeListener[resource.toString()] = model.addListener2('dispose', () => this.remove(resource));
this.mapResourceToDisposeListener[resource.toString()] = model.onDispose(() => this.remove(resource));
}
public remove(resource: URI): void {
......
......@@ -12,6 +12,7 @@ import { Action } from 'vs/base/common/actions';
import { isPromiseCanceledError, create as createError } from 'vs/base/common/errors';
import * as mime from 'vs/base/common/mime';
import * as paths from 'vs/base/common/paths';
import { once } from 'vs/base/common/event';
import { EventEmitter } from 'vs/base/common/eventEmitter';
import { EditorInput } from 'vs/workbench/common/editor';
import { IFileStatus, IGitServiceError, GitErrorCodes, Status, StatusType, AutoFetcherState, IGitConfiguration, IAutoFetcher, ServiceEvents, ServiceState,
......@@ -132,7 +133,8 @@ class EditorInputCache {
return TPromise.as(new GitDiffEditorInput(localize('gitMergeChanges', "{0} (merge) ↔ {1}", fileSegment, fileSegment), localize('gitMergeChangesDesc', "{0} - Merge changes", folderSegment), leftInput, rightInput, status));
}
}).then((editorInput: EditorInput) => {
editorInput.addOneTimeDisposableListener('dispose', () => {
const onceDispose = once(editorInput.onDispose);
onceDispose(() => {
delete this.cache[status.getId()];
});
......
......@@ -90,7 +90,7 @@ class EditorInputCache {
this.createRightInput(fileMatch)]).then(inputs => {
const [left, right] = inputs;
let editorInput= new DiffEditorInput(nls.localize('fileReplaceChanges', "{0} ↔ {1} (Replace Preview)", fileMatch.name(), fileMatch.name()), undefined, <EditorInput>left, <EditorInput>right);
editorInput.addListener2('dispose', () => this.cleanInput(fileMatch.resource()));
editorInput.onDispose(() => this.cleanInput(fileMatch.resource()));
return editorInput;
});
}
......
......@@ -9,7 +9,6 @@ import errors = require('vs/base/common/errors');
import platform = require('vs/base/common/platform');
import nls = require('vs/nls');
import product from 'vs/platform/product';
import {EventType} from 'vs/base/common/events';
import {IEditor as IBaseEditor} from 'vs/platform/editor/common/editor';
import {EditorInput, IGroupEvent, IEditorRegistry, Extensions} from 'vs/workbench/common/editor';
import {BaseTextEditor} from 'vs/workbench/browser/parts/editor/textEditor';
......@@ -23,6 +22,7 @@ import {IDisposable, dispose} from 'vs/base/common/lifecycle';
import {IStorageService, StorageScope} from 'vs/platform/storage/common/storage';
import {ILifecycleService} from 'vs/platform/lifecycle/common/lifecycle';
import {Registry} from 'vs/platform/platform';
import {once} from 'vs/base/common/event';
import {IInstantiationService} from 'vs/platform/instantiation/common/instantiation';
import {IEditorGroupService} from 'vs/workbench/services/group/common/groupService';
import {IEnvironmentService} from 'vs/platform/environment/common/environment';
......@@ -276,7 +276,8 @@ export class HistoryService extends BaseHistoryService implements IHistoryServic
}
// Restore on dispose
editor.addOneTimeDisposableListener(EventType.DISPOSE, () => {
const onceDispose = once(editor.onDispose);
onceDispose(() => {
this.restoreInRecentlyClosed(editor);
});
}
......@@ -360,7 +361,8 @@ export class HistoryService extends BaseHistoryService implements IHistoryServic
}
// Restore on dispose
input.addOneTimeDisposableListener(EventType.DISPOSE, () => {
const onceDispose = once(input.onDispose);
onceDispose(() => {
this.restoreInHistory(input);
});
}
......@@ -498,7 +500,8 @@ export class HistoryService extends BaseHistoryService implements IHistoryServic
}
// Restore on dispose
input.addOneTimeDisposableListener(EventType.DISPOSE, () => {
const onceDispose = once(input.onDispose);
onceDispose(() => {
this.restoreInStack(input);
});
}
......
......@@ -6,10 +6,9 @@
import URI from 'vs/base/common/uri';
import {createDecorator, IInstantiationService} from 'vs/platform/instantiation/common/instantiation';
import {EventType} from 'vs/base/common/events';
import arrays = require('vs/base/common/arrays');
import {UntitledEditorInput} from 'vs/workbench/common/editor/untitledEditorInput';
import Event, {Emitter} from 'vs/base/common/event';
import Event, {Emitter, once} from 'vs/base/common/event';
export const IUntitledEditorService = createDecorator<IUntitledEditorService>('untitledEditorService');
......@@ -158,7 +157,8 @@ export class UntitledEditorService implements IUntitledEditorService {
});
// Remove from cache on dispose
input.addOneTimeDisposableListener(EventType.DISPOSE, () => {
const onceDispose = once(input.onDispose);
onceDispose(() => {
delete UntitledEditorService.CACHE[input.getResource().toString()];
delete UntitledEditorService.KNOWN_ASSOCIATED_FILE_PATHS[input.getResource().toString()];
listener.dispose();
......
......@@ -140,7 +140,7 @@ suite('Workbench BaseEditor', () => {
e.setVisible(true);
assert(e.isVisible());
input.addListener2('dispose', () => {
input.onDispose(() => {
assert(false);
});
e.dispose();
......
......@@ -35,7 +35,7 @@ suite('Workbench - EditorInput', () => {
assert(!input.matches(null));
assert(!input.getName());
input.addListener2('dispose', function () {
input.onDispose(() => {
assert(true);
counter++;
});
......@@ -47,13 +47,13 @@ suite('Workbench - EditorInput', () => {
test('DiffEditorInput', function () {
let counter = 0;
let input = new MyEditorInput();
input.addListener2('dispose', function () {
input.onDispose(() => {
assert(true);
counter++;
});
let otherInput = new MyEditorInput();
otherInput.addListener2('dispose', function () {
otherInput.onDispose(() => {
assert(true);
counter++;
});
......@@ -76,7 +76,7 @@ suite('Workbench - EditorInput', () => {
let otherInput = new MyEditorInput();
let diffInput = new DiffEditorInput('name', 'description', input, otherInput);
diffInput.addListener2('dispose', function () {
diffInput.onDispose(() => {
counter++;
assert(true);
});
......@@ -87,7 +87,7 @@ suite('Workbench - EditorInput', () => {
otherInput = new MyEditorInput();
let diffInput2 = new DiffEditorInput('name', 'description', input, otherInput);
diffInput2.addListener2('dispose', function () {
diffInput2.onDispose(() => {
counter++;
assert(true);
});
......
......@@ -30,10 +30,20 @@ suite('Workbench - EditorModel', () => {
});
test('EditorModel', function (done) {
let counter = 0;
let m = new MyEditorModel();
m.onDispose(() => {
assert(true);
counter++;
});
m.load().then(model => {
assert(model === m);
assert.strictEqual(m.isResolved(), true);
m.dispose();
assert.equal(counter, 1);
}).done(() => done());
});
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册