提交 93773614 编写于 作者: B Benjamin Pasero

first cut of handling dirty editors on close

上级 90186406
...@@ -23,7 +23,7 @@ import {Scope} from 'vs/workbench/browser/actionBarRegistry'; ...@@ -23,7 +23,7 @@ import {Scope} from 'vs/workbench/browser/actionBarRegistry';
import {Part} from 'vs/workbench/browser/part'; import {Part} from 'vs/workbench/browser/part';
import {EventType as WorkbenchEventType, EditorInputEvent, EditorEvent} from 'vs/workbench/common/events'; import {EventType as WorkbenchEventType, EditorInputEvent, EditorEvent} from 'vs/workbench/common/events';
import {IEditorRegistry, Extensions as EditorExtensions, BaseEditor, EditorDescriptor} from 'vs/workbench/browser/parts/editor/baseEditor'; import {IEditorRegistry, Extensions as EditorExtensions, BaseEditor, EditorDescriptor} from 'vs/workbench/browser/parts/editor/baseEditor';
import {EditorInput, EditorOptions, TextEditorOptions} from 'vs/workbench/common/editor'; import {EditorInput, EditorOptions, TextEditorOptions, ConfirmResult} from 'vs/workbench/common/editor';
import {BaseTextEditor} from 'vs/workbench/browser/parts/editor/textEditor'; import {BaseTextEditor} from 'vs/workbench/browser/parts/editor/textEditor';
import {SideBySideEditorControl, Rochade, ISideBySideEditorControl, ProgressState, ITitleAreaState} from 'vs/workbench/browser/parts/editor/sideBySideEditorControl'; import {SideBySideEditorControl, Rochade, ISideBySideEditorControl, ProgressState, ITitleAreaState} from 'vs/workbench/browser/parts/editor/sideBySideEditorControl';
import {WorkbenchProgressService} from 'vs/workbench/services/progress/browser/progressService'; import {WorkbenchProgressService} from 'vs/workbench/services/progress/browser/progressService';
...@@ -467,6 +467,7 @@ export class EditorPart extends Part implements IEditorPart { ...@@ -467,6 +467,7 @@ export class EditorPart extends Part implements IEditorPart {
this.sideBySideControl.updateProgress(position, ProgressState.DONE); this.sideBySideControl.updateProgress(position, ProgressState.DONE);
// Event
this.emit(WorkbenchEventType.EDITOR_SET_INPUT_ERROR, new EditorEvent(editor, editor.getId(), input, options, position)); this.emit(WorkbenchEventType.EDITOR_SET_INPUT_ERROR, new EditorEvent(editor, editor.getId(), input, options, position));
// Recover from this error by closing the editor if the attempt of setInput failed and we are not having any previous input // Recover from this error by closing the editor if the attempt of setInput failed and we are not having any previous input
...@@ -503,37 +504,59 @@ export class EditorPart extends Part implements IEditorPart { ...@@ -503,37 +504,59 @@ export class EditorPart extends Part implements IEditorPart {
} }
// Closing inactive editor is just a model update // Closing inactive editor is just a model update
group.closeEditor(input); this.doCloseInactiveEditor(input, position);
} }
private doCloseActiveEditor(position: Position): TPromise<void> { private doCloseActiveEditor(position: Position): TPromise<void> {
// Update visible inputs for position // Check for dirty and veto
this.visibleInputs[position] = null; const input = this.visibleInputs[position];
return this.handleDirty([input]).then(veto => {
if (veto) {
return;
}
// Dispose previous input listener if any // Update visible inputs for position
if (this.visibleInputListeners[position]) { this.visibleInputs[position] = null;
this.visibleInputListeners[position]();
this.visibleInputListeners[position] = null;
}
// Reset counter // Dispose previous input listener if any
this.editorSetInputErrorCounter[position] = 0; if (this.visibleInputListeners[position]) {
this.visibleInputListeners[position]();
this.visibleInputListeners[position] = null;
}
// Update stacks model // Reset counter
const group = this.groupAt(position); this.editorSetInputErrorCounter[position] = 0;
group.closeEditor(group.activeEditor);
// Close group is this is the last editor in group // Update stacks model
if (group.count === 0) { const group = this.groupAt(position);
return this.doCloseGroup(position); group.closeEditor(group.activeEditor);
}
// Otherwise open next active // Close group is this is the last editor in group
return this.openEditor(group.activeEditor, null, position).then(null, (error) => { if (group.count === 0) {
return this.doCloseGroup(position);
}
// in case of an error, continue closing // Otherwise open next active
return this.doCloseActiveEditor(position); return this.openEditor(group.activeEditor, null, position).then(null, (error) => {
// in case of an error, continue closing
return this.doCloseActiveEditor(position);
});
});
}
private doCloseInactiveEditor(input: EditorInput, position: Position): TPromise<void> {
// Check for dirty and veto
return this.handleDirty([input]).then(veto => {
if (veto) {
return;
}
// Closing inactive editor is just a model update
const group = this.groupAt(position);
group.closeEditor(input);
}); });
} }
...@@ -610,30 +633,44 @@ export class EditorPart extends Part implements IEditorPart { ...@@ -610,30 +633,44 @@ export class EditorPart extends Part implements IEditorPart {
const group = this.groupAt(position); const group = this.groupAt(position);
// Close all editors in group // Check for dirty and veto
if (!except) { let editorsToClose: EditorInput[];
if (!direction) {
editorsToClose = group.getEditors().filter(e => !except || !e.matches(except));
} else {
editorsToClose = (direction === Direction.LEFT) ? group.getEditors().slice(0, group.indexOf(except)) : group.getEditors().slice(group.indexOf(except) + 1);
}
// Update stacks model: remove all non active editors first to prevent opening the next editor in group return this.handleDirty(editorsToClose).then(veto => {
group.closeEditors(group.activeEditor); if (veto) {
return;
}
// Now close active editor in group which will close the group // Close all editors in group
return this.doCloseActiveEditor(position); if (!except) {
}
// Update stacks model: remove all non active editors first to prevent opening the next editor in group
group.closeEditors(group.activeEditor);
// Close all editors in group except active one // Now close active editor in group which will close the group
if (except.matches(group.activeEditor)) { return this.doCloseActiveEditor(position);
}
// Update stacks model: close non active editors supporting the direction // Close all editors in group except active one
group.closeEditors(group.activeEditor, direction); if (except.matches(group.activeEditor)) {
// No UI update needed // Update stacks model: close non active editors supporting the direction
return TPromise.as(null); group.closeEditors(group.activeEditor, direction);
}
// No UI update needed
return TPromise.as(null);
}
// Finally: we are asked to close editors around a non-active editor // Finally: we are asked to close editors around a non-active editor
// Thus we make the non-active one active and then close the others // Thus we make the non-active one active and then close the others
return this.openEditor(except, null, position).then(() => { return this.openEditor(except, null, position).then(() => {
return this.closeEditors(position, except, direction); return this.closeEditors(position, except, direction);
});
}); });
} }
...@@ -648,6 +685,38 @@ export class EditorPart extends Part implements IEditorPart { ...@@ -648,6 +685,38 @@ export class EditorPart extends Part implements IEditorPart {
return TPromise.join(editors.map(e => this.closeEditors(e.position))).then(() => void 0); return TPromise.join(editors.map(e => this.closeEditors(e.position))).then(() => void 0);
} }
private handleDirty(inputs: EditorInput[]): TPromise<boolean /* veto */> {
if (!inputs.length) {
return TPromise.as(false); // no veto
}
return this.doHandleDirty(inputs.shift()).then(veto => {
if (veto) {
return veto;
}
return this.handleDirty(inputs);
});
}
private doHandleDirty(input: EditorInput): TPromise<boolean /* veto */> {
if (!input || !input.isDirty()) {
return TPromise.as(false); // no veto
}
const res = input.confirmSave();
switch (res) {
case ConfirmResult.SAVE:
return input.save().then(ok => !ok);
case ConfirmResult.DONT_SAVE:
return input.revert().then(ok => !ok);
case ConfirmResult.CANCEL:
return TPromise.as(true); // veto
}
}
public getStacksModel(): EditorStacksModel { public getStacksModel(): EditorStacksModel {
return this.stacksModel; return this.stacksModel;
} }
...@@ -902,24 +971,35 @@ export class EditorPart extends Part implements IEditorPart { ...@@ -902,24 +971,35 @@ export class EditorPart extends Part implements IEditorPart {
return; return;
} }
let closeActivePromise: TPromise<void> = TPromise.as(null); // Unpinning an editor closes the preview editor if we have any
let handlePreviewEditor: TPromise<boolean> = TPromise.as(false);
// The active editor is the preview editor and we are asked to make if (group.previewEditor) {
// another editor the preview editor. So we need to take care of closing handlePreviewEditor = this.handleDirty([group.previewEditor]);
// the active editor first
if (group.isPreview(group.activeEditor) && !group.activeEditor.matches(input)) {
closeActivePromise = this.doCloseActiveEditor(position);
} }
closeActivePromise.done(() => { handlePreviewEditor.done(veto => {
if (veto) {
return;
}
// Update stacks model // The active editor is the preview editor and we are asked to make
group.unpin(input); // another editor the preview editor. So we need to take care of closing
// the active editor first
let closeActivePromise: TPromise<void> = TPromise.as(null);
if (group.isPreview(group.activeEditor) && !group.activeEditor.matches(input)) {
closeActivePromise = this.doCloseActiveEditor(position);
}
// Update UI closeActivePromise.done(() => {
this.sideBySideControl.updateTitleArea({ position, preview: group.previewEditor });
}, errors.onUnexpectedError); // Update stacks model
group.unpin(input);
// Update UI
this.sideBySideControl.updateTitleArea({ position, preview: group.previewEditor });
}, errors.onUnexpectedError);
});
} }
} }
......
...@@ -38,6 +38,12 @@ export interface IInputStatus { ...@@ -38,6 +38,12 @@ export interface IInputStatus {
decoration?: string; decoration?: string;
} }
export enum ConfirmResult {
SAVE,
DONT_SAVE,
CANCEL
}
/** /**
* Editor inputs are lightweight objects that can be passed to the workbench API to open inside the editor part. * 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. * Each editor input is mapped to an editor that is capable of opening it through the Platform facade.
...@@ -103,6 +109,40 @@ export abstract class EditorInput extends EventEmitter implements IEditorInput { ...@@ -103,6 +109,40 @@ export abstract class EditorInput extends EventEmitter implements IEditorInput {
*/ */
public abstract resolve(refresh?: boolean): TPromise<EditorModel>; public abstract resolve(refresh?: boolean): TPromise<EditorModel>;
/**
* An editor that is dirty will be asked to be saved once it closes.
*/
public isDirty(): boolean {
return false;
}
/**
* Subclasses should bring up a proper dialog for the user if the editor is dirty and return the result.
*/
public confirmSave(): ConfirmResult {
return ConfirmResult.DONT_SAVE;
}
/**
* Saves the editor if it is dirty. Subclasses return a promise with a boolean indicating the success of the operation.
*/
public save(): TPromise<boolean> {
return TPromise.as(true);
}
/**
* Reverts the editor if it is dirty. Subclasses return a promise with a boolean indicating the success of the operation.
*/
public revert(): TPromise<boolean> {
return TPromise.as(true);
}
/**
* Called when the editor is closed. Subclasses can free resources as needed.
*/
public close(): void {
}
/** /**
* Called when an editor input is no longer needed. Allows to free up any resources taken by * Called when an editor input is no longer needed. Allows to free up any resources taken by
* resolving the editor input. * resolving the editor input.
...@@ -222,6 +262,27 @@ export abstract class BaseDiffEditorInput extends EditorInput { ...@@ -222,6 +262,27 @@ export abstract class BaseDiffEditorInput extends EditorInput {
public getModifiedInput(): EditorInput { public getModifiedInput(): EditorInput {
return this.modifiedInput; return this.modifiedInput;
} }
public isDirty(): boolean {
return this._modifiedInput.isDirty();
}
public confirmSave(): ConfirmResult {
return this._modifiedInput.confirmSave();
}
public save(): TPromise<boolean> {
return this._modifiedInput.save();
}
public revert(): TPromise<boolean> {
return this._modifiedInput.revert();
}
public close(): void {
this._originalInput.close();
this._modifiedInput.close();
}
} }
/** /**
......
...@@ -317,6 +317,9 @@ export class EditorGroup implements IEditorGroup { ...@@ -317,6 +317,9 @@ export class EditorGroup implements IEditorGroup {
this.preview = null; this.preview = null;
} }
// Close it
editor.close();
// Remove from arrays // Remove from arrays
this.splice(index, true); this.splice(index, true);
......
...@@ -9,13 +9,15 @@ import URI from 'vs/base/common/uri'; ...@@ -9,13 +9,15 @@ import URI from 'vs/base/common/uri';
import {isUnspecific, guessMimeTypes, MIME_TEXT, suggestFilename} from 'vs/base/common/mime'; import {isUnspecific, guessMimeTypes, MIME_TEXT, suggestFilename} from 'vs/base/common/mime';
import labels = require('vs/base/common/labels'); import labels = require('vs/base/common/labels');
import paths = require('vs/base/common/paths'); import paths = require('vs/base/common/paths');
import {UntitledEditorInput as AbstractUntitledEditorInput, EditorModel, EncodingMode, IInputStatus} from 'vs/workbench/common/editor'; import {UntitledEditorInput as AbstractUntitledEditorInput, EditorModel, EncodingMode, IInputStatus, ConfirmResult} from 'vs/workbench/common/editor';
import {UntitledEditorModel} from 'vs/workbench/common/editor/untitledEditorModel'; import {UntitledEditorModel} from 'vs/workbench/common/editor/untitledEditorModel';
import {IInstantiationService} from 'vs/platform/instantiation/common/instantiation'; import {IInstantiationService} from 'vs/platform/instantiation/common/instantiation';
import {ILifecycleService} from 'vs/platform/lifecycle/common/lifecycle'; import {ILifecycleService} from 'vs/platform/lifecycle/common/lifecycle';
import {IWorkspaceContextService} from 'vs/platform/workspace/common/workspace'; import {IWorkspaceContextService} from 'vs/platform/workspace/common/workspace';
import {IModeService} from 'vs/editor/common/services/modeService'; import {IModeService} from 'vs/editor/common/services/modeService';
import {ITextFileService} from 'vs/workbench/parts/files/common/files'; // TODO@Ben layer breaker
/** /**
* An editor input to be used for untitled text buffers. * An editor input to be used for untitled text buffers.
*/ */
...@@ -36,7 +38,8 @@ export class UntitledEditorInput extends AbstractUntitledEditorInput { ...@@ -36,7 +38,8 @@ export class UntitledEditorInput extends AbstractUntitledEditorInput {
@IInstantiationService private instantiationService: IInstantiationService, @IInstantiationService private instantiationService: IInstantiationService,
@ILifecycleService private lifecycleService: ILifecycleService, @ILifecycleService private lifecycleService: ILifecycleService,
@IWorkspaceContextService private contextService: IWorkspaceContextService, @IWorkspaceContextService private contextService: IWorkspaceContextService,
@IModeService private modeService: IModeService @IModeService private modeService: IModeService,
@ITextFileService private textFileService: ITextFileService
) { ) {
super(); super();
...@@ -74,6 +77,18 @@ export class UntitledEditorInput extends AbstractUntitledEditorInput { ...@@ -74,6 +77,18 @@ export class UntitledEditorInput extends AbstractUntitledEditorInput {
return null; return null;
} }
public confirmSave(): ConfirmResult {
return this.textFileService.confirmSave([this.resource]);
}
public save(): TPromise<boolean> {
return this.textFileService.save(this.resource);
}
public revert(): TPromise<boolean> {
return this.textFileService.revert(this.resource);
}
public suggestFileName(): string { public suggestFileName(): string {
if (!this.hasAssociatedFilePath) { if (!this.hasAssociatedFilePath) {
let mime = this.getMime(); let mime = this.getMime();
......
...@@ -14,7 +14,7 @@ import labels = require('vs/base/common/labels'); ...@@ -14,7 +14,7 @@ import labels = require('vs/base/common/labels');
import URI from 'vs/base/common/uri'; import URI from 'vs/base/common/uri';
import strings = require('vs/base/common/strings'); import strings = require('vs/base/common/strings');
import assert = require('vs/base/common/assert'); import assert = require('vs/base/common/assert');
import {EditorModel, IInputStatus, EncodingMode} from 'vs/workbench/common/editor'; import {EditorModel, IInputStatus, EncodingMode, ConfirmResult} from 'vs/workbench/common/editor';
import {IEditorRegistry, Extensions, EditorDescriptor} from 'vs/workbench/browser/parts/editor/baseEditor'; import {IEditorRegistry, Extensions, EditorDescriptor} from 'vs/workbench/browser/parts/editor/baseEditor';
import {BinaryEditorModel} from 'vs/workbench/common/editor/binaryEditorModel'; import {BinaryEditorModel} from 'vs/workbench/common/editor/binaryEditorModel';
import {IFileOperationResult, FileOperationResult} from 'vs/platform/files/common/files'; import {IFileOperationResult, FileOperationResult} from 'vs/platform/files/common/files';
...@@ -175,6 +175,22 @@ export class FileEditorInput extends CommonFileEditorInput { ...@@ -175,6 +175,22 @@ export class FileEditorInput extends CommonFileEditorInput {
return null; return null;
} }
public isDirty(): boolean {
return this.textFileService.isDirty(this.resource);
}
public confirmSave(): ConfirmResult {
return this.textFileService.confirmSave([this.resource]);
}
public save(): TPromise<boolean> {
return this.textFileService.save(this.resource);
}
public revert(): TPromise<boolean> {
return this.textFileService.revert(this.resource);
}
public getPreferredEditorId(candidates: string[]): string { public getPreferredEditorId(candidates: string[]): string {
let editorRegistry = (<IEditorRegistry>Registry.as(Extensions.Editors)); let editorRegistry = (<IEditorRegistry>Registry.as(Extensions.Editors));
......
...@@ -25,10 +25,10 @@ import {MessageType, IInputValidator} from 'vs/base/browser/ui/inputbox/inputBox ...@@ -25,10 +25,10 @@ import {MessageType, IInputValidator} from 'vs/base/browser/ui/inputbox/inputBox
import {ITree, IHighlightEvent} from 'vs/base/parts/tree/browser/tree'; import {ITree, IHighlightEvent} from 'vs/base/parts/tree/browser/tree';
import {dispose, IDisposable} from 'vs/base/common/lifecycle'; import {dispose, IDisposable} from 'vs/base/common/lifecycle';
import {EventType as WorkbenchEventType, EditorEvent} from 'vs/workbench/common/events'; import {EventType as WorkbenchEventType, EditorEvent} from 'vs/workbench/common/events';
import Files = require('vs/workbench/parts/files/common/files'); import {LocalFileChangeEvent, VIEWLET_ID, ITextFileService, TextFileChangeEvent, ITextFileOperationResult, IWorkingFileModelChangeEvent, IWorkingFileEntry, IWorkingFilesModel, EventType as FileEventType} from 'vs/workbench/parts/files/common/files';
import {IFileService, IFileStat, IImportResult} from 'vs/platform/files/common/files'; import {IFileService, IFileStat, IImportResult} from 'vs/platform/files/common/files';
import {DiffEditorInput, toDiffLabel} from 'vs/workbench/common/editor/diffEditorInput'; import {DiffEditorInput, toDiffLabel} from 'vs/workbench/common/editor/diffEditorInput';
import {asFileEditorInput, getUntitledOrFileResource, TextEditorOptions, EditorOptions, UntitledEditorInput} from 'vs/workbench/common/editor'; import {asFileEditorInput, getUntitledOrFileResource, TextEditorOptions, EditorOptions, UntitledEditorInput, ConfirmResult} from 'vs/workbench/common/editor';
import {IEditorSelection} from 'vs/editor/common/editorCommon'; import {IEditorSelection} from 'vs/editor/common/editorCommon';
import {FileEditorInput} from 'vs/workbench/parts/files/browser/editors/fileEditorInput'; import {FileEditorInput} from 'vs/workbench/parts/files/browser/editors/fileEditorInput';
import {FileStat, NewStatPlaceholder} from 'vs/workbench/parts/files/common/explorerViewModel'; import {FileStat, NewStatPlaceholder} from 'vs/workbench/parts/files/common/explorerViewModel';
...@@ -50,8 +50,6 @@ import {IMessageService, IMessageWithAction, IConfirmation, Severity, CancelActi ...@@ -50,8 +50,6 @@ import {IMessageService, IMessageWithAction, IConfirmation, Severity, CancelActi
import {IWorkspaceContextService} from 'vs/platform/workspace/common/workspace'; import {IWorkspaceContextService} from 'vs/platform/workspace/common/workspace';
import {KeyMod, KeyCode, Keybinding} from 'vs/base/common/keyCodes'; import {KeyMod, KeyCode, Keybinding} from 'vs/base/common/keyCodes';
import ITextFileService = Files.ITextFileService;
export interface IEditableData { export interface IEditableData {
action: IAction; action: IAction;
validator: IInputValidator; validator: IInputValidator;
...@@ -155,11 +153,11 @@ export class BaseFileAction extends Action { ...@@ -155,11 +153,11 @@ export class BaseFileAction extends Action {
protected handleDirty(): TPromise<boolean /* cancel */> { protected handleDirty(): TPromise<boolean /* cancel */> {
if (this.textFileService.isDirty(this._element.resource)) { if (this.textFileService.isDirty(this._element.resource)) {
let res = this.textFileService.confirmSave([this._element.resource]); let res = this.textFileService.confirmSave([this._element.resource]);
if (res === Files.ConfirmResult.SAVE) { if (res === ConfirmResult.SAVE) {
return this.textFileService.save(this._element.resource).then(() => false); return this.textFileService.save(this._element.resource).then(() => false);
} }
if (res === Files.ConfirmResult.DONT_SAVE) { if (res === ConfirmResult.DONT_SAVE) {
return this.textFileService.revert(this._element.resource).then(() => false); return this.textFileService.revert(this._element.resource).then(() => false);
} }
...@@ -325,7 +323,7 @@ export abstract class BaseRenameAction extends BaseFileAction { ...@@ -325,7 +323,7 @@ export abstract class BaseRenameAction extends BaseFileAction {
before = this.element.clone(); // Clone element to not expose viewers element to listeners before = this.element.clone(); // Clone element to not expose viewers element to listeners
} }
this.eventService.emit('files.internal:fileChanged', new Files.LocalFileChangeEvent(before, stat)); this.eventService.emit('files.internal:fileChanged', new LocalFileChangeEvent(before, stat));
} }
} }
...@@ -524,7 +522,7 @@ export abstract class BaseGlobalNewAction extends Action { ...@@ -524,7 +522,7 @@ export abstract class BaseGlobalNewAction extends Action {
} }
public run(): TPromise<any> { public run(): TPromise<any> {
return this.viewletService.openViewlet(Files.VIEWLET_ID, true).then((viewlet) => { return this.viewletService.openViewlet(VIEWLET_ID, true).then((viewlet) => {
return TPromise.timeout(100).then(() => { // use a timeout to prevent the explorer from revealing the active file return TPromise.timeout(100).then(() => { // use a timeout to prevent the explorer from revealing the active file
viewlet.focus(); viewlet.focus();
...@@ -730,7 +728,7 @@ export class BaseDeleteFileAction extends BaseFileAction { ...@@ -730,7 +728,7 @@ export class BaseDeleteFileAction extends BaseFileAction {
// Since a delete operation can take a while we want to emit the event proactively to avoid issues // Since a delete operation can take a while we want to emit the event proactively to avoid issues
// with stale entries in the explorer tree. // with stale entries in the explorer tree.
this.eventService.emit('files.internal:fileChanged', new Files.LocalFileChangeEvent(this.element.clone(), null)); this.eventService.emit('files.internal:fileChanged', new LocalFileChangeEvent(this.element.clone(), null));
// Call function // Call function
let servicePromise = this.fileService.del(this.element.resource, this.useTrash).then(() => { let servicePromise = this.fileService.del(this.element.resource, this.useTrash).then(() => {
...@@ -748,7 +746,7 @@ export class BaseDeleteFileAction extends BaseFileAction { ...@@ -748,7 +746,7 @@ export class BaseDeleteFileAction extends BaseFileAction {
this.onErrorWithRetry(error, () => this.run(), extraAction); this.onErrorWithRetry(error, () => this.run(), extraAction);
// Since the delete failed, best we can do is to refresh the explorer from the root to show the current state of files. // Since the delete failed, best we can do is to refresh the explorer from the root to show the current state of files.
let event = new Files.LocalFileChangeEvent(new FileStat(this.contextService.getWorkspace().resource, true, true), new FileStat(this.contextService.getWorkspace().resource, true, true)); let event = new LocalFileChangeEvent(new FileStat(this.contextService.getWorkspace().resource, true, true), new FileStat(this.contextService.getWorkspace().resource, true, true));
this.eventService.emit('files.internal:fileChanged', event); this.eventService.emit('files.internal:fileChanged', event);
// Focus back to tree // Focus back to tree
...@@ -890,7 +888,7 @@ export class ImportFileAction extends BaseFileAction { ...@@ -890,7 +888,7 @@ export class ImportFileAction extends BaseFileAction {
// Emit Deleted Event if file gets replaced unless it is the same file // Emit Deleted Event if file gets replaced unless it is the same file
let oldFile = targetNames[isLinux ? file.name : file.name.toLowerCase()]; let oldFile = targetNames[isLinux ? file.name : file.name.toLowerCase()];
if (oldFile && oldFile.resource.fsPath !== result.stat.resource.fsPath) { if (oldFile && oldFile.resource.fsPath !== result.stat.resource.fsPath) {
this.eventService.emit('files.internal:fileChanged', new Files.LocalFileChangeEvent(oldFile, null)); this.eventService.emit('files.internal:fileChanged', new LocalFileChangeEvent(oldFile, null));
} }
// Emit Import Event // Emit Import Event
...@@ -917,7 +915,7 @@ export class ImportFileAction extends BaseFileAction { ...@@ -917,7 +915,7 @@ export class ImportFileAction extends BaseFileAction {
} }
/** File import event is emitted when a file is import into the workbench. */ /** File import event is emitted when a file is import into the workbench. */
export class FileImportedEvent extends Files.LocalFileChangeEvent { export class FileImportedEvent extends LocalFileChangeEvent {
private isNew: boolean; private isNew: boolean;
constructor(stat?: IFileStat, isNew?: boolean, originalEvent?: Event) { constructor(stat?: IFileStat, isNew?: boolean, originalEvent?: Event) {
...@@ -1083,7 +1081,7 @@ export class DuplicateFileAction extends BaseFileAction { ...@@ -1083,7 +1081,7 @@ export class DuplicateFileAction extends BaseFileAction {
// Copy File and emit event // Copy File and emit event
let result = this.fileService.copyFile(this.element.resource, this.findTarget()).then((stat: IFileStat) => { let result = this.fileService.copyFile(this.element.resource, this.findTarget()).then((stat: IFileStat) => {
this.eventService.emit('files.internal:fileChanged', new Files.LocalFileChangeEvent(null, stat)); this.eventService.emit('files.internal:fileChanged', new LocalFileChangeEvent(null, stat));
}, (error: any) => { }, (error: any) => {
this.onError(error); this.onError(error);
}); });
...@@ -1544,10 +1542,10 @@ export abstract class BaseSaveAllAction extends BaseActionWithErrorReporting { ...@@ -1544,10 +1542,10 @@ export abstract class BaseSaveAllAction extends BaseActionWithErrorReporting {
private registerListeners(): void { private registerListeners(): void {
// listen to files being changed locally // listen to files being changed locally
this.toDispose.push(this.eventService.addListener2(Files.EventType.FILE_DIRTY, (e: Files.TextFileChangeEvent) => this.updateEnablement(true))); this.toDispose.push(this.eventService.addListener2(FileEventType.FILE_DIRTY, (e: TextFileChangeEvent) => this.updateEnablement(true)));
this.toDispose.push(this.eventService.addListener2(Files.EventType.FILE_SAVED, (e: Files.TextFileChangeEvent) => this.updateEnablement(false))); this.toDispose.push(this.eventService.addListener2(FileEventType.FILE_SAVED, (e: TextFileChangeEvent) => this.updateEnablement(false)));
this.toDispose.push(this.eventService.addListener2(Files.EventType.FILE_REVERTED, (e: Files.TextFileChangeEvent) => this.updateEnablement(false))); this.toDispose.push(this.eventService.addListener2(FileEventType.FILE_REVERTED, (e: TextFileChangeEvent) => this.updateEnablement(false)));
this.toDispose.push(this.eventService.addListener2(Files.EventType.FILE_SAVE_ERROR, (e: Files.TextFileChangeEvent) => this.updateEnablement(true))); this.toDispose.push(this.eventService.addListener2(FileEventType.FILE_SAVE_ERROR, (e: TextFileChangeEvent) => this.updateEnablement(true)));
if (this.includeUntitled()) { if (this.includeUntitled()) {
this.toDispose.push(this.eventService.addListener2(WorkbenchEventType.UNTITLED_FILE_DIRTY, () => this.updateEnablement(true))); this.toDispose.push(this.eventService.addListener2(WorkbenchEventType.UNTITLED_FILE_DIRTY, () => this.updateEnablement(true)));
...@@ -1765,8 +1763,8 @@ export class ReopenClosedFileAction extends Action { ...@@ -1765,8 +1763,8 @@ export class ReopenClosedFileAction extends Action {
} }
public run(): TPromise<any> { public run(): TPromise<any> {
let workingFilesModel: Files.IWorkingFilesModel = this.textFileService.getWorkingFilesModel(); let workingFilesModel: IWorkingFilesModel = this.textFileService.getWorkingFilesModel();
let entry: Files.IWorkingFileEntry = workingFilesModel.popLastClosedEntry(); let entry: IWorkingFileEntry = workingFilesModel.popLastClosedEntry();
if (entry === null) { if (entry === null) {
return TPromise.as(true); return TPromise.as(true);
...@@ -1825,12 +1823,12 @@ export abstract class BaseCloseWorkingFileAction extends Action { ...@@ -1825,12 +1823,12 @@ export abstract class BaseCloseWorkingFileAction extends Action {
isDirty = this.textFileService.isDirty(); isDirty = this.textFileService.isDirty();
} }
let saveOrRevertPromise: TPromise<Files.ITextFileOperationResult> = TPromise.as(null); let saveOrRevertPromise: TPromise<ITextFileOperationResult> = TPromise.as(null);
if (isDirty) { if (isDirty) {
let confirmResult = this.textFileService.confirmSave(this.elements); let confirmResult = this.textFileService.confirmSave(this.elements);
switch (confirmResult) { switch (confirmResult) {
case Files.ConfirmResult.SAVE: case ConfirmResult.SAVE:
if (this.elements) { if (this.elements) {
saveOrRevertPromise = this.textFileService.saveAll(this.elements); saveOrRevertPromise = this.textFileService.saveAll(this.elements);
} else { } else {
...@@ -1838,7 +1836,7 @@ export abstract class BaseCloseWorkingFileAction extends Action { ...@@ -1838,7 +1836,7 @@ export abstract class BaseCloseWorkingFileAction extends Action {
} }
break; break;
case Files.ConfirmResult.DONT_SAVE: case ConfirmResult.DONT_SAVE:
if (this.elements) { if (this.elements) {
saveOrRevertPromise = this.textFileService.revertAll(this.elements); saveOrRevertPromise = this.textFileService.revertAll(this.elements);
} else { } else {
...@@ -1846,12 +1844,12 @@ export abstract class BaseCloseWorkingFileAction extends Action { ...@@ -1846,12 +1844,12 @@ export abstract class BaseCloseWorkingFileAction extends Action {
} }
break; break;
case Files.ConfirmResult.CANCEL: case ConfirmResult.CANCEL:
return TPromise.as(null); return TPromise.as(null);
} }
} }
return saveOrRevertPromise.then((result?: Files.ITextFileOperationResult) => { return saveOrRevertPromise.then((result?: ITextFileOperationResult) => {
// Collect resources to dispose // Collect resources to dispose
let resourcesToDispose: URI[] = []; let resourcesToDispose: URI[] = [];
...@@ -1922,7 +1920,7 @@ export class CloseAllWorkingFilesAction extends BaseCloseWorkingFileAction { ...@@ -1922,7 +1920,7 @@ export class CloseAllWorkingFilesAction extends BaseCloseWorkingFileAction {
return super.run().then(() => closeNonFileEditors(this.editorService)); // close non file editors too return super.run().then(() => closeNonFileEditors(this.editorService)); // close non file editors too
} }
private onModelChange(event: Files.IWorkingFileModelChangeEvent): void { private onModelChange(event: IWorkingFileModelChangeEvent): void {
this.enabled = (this.model.count() > 0); this.enabled = (this.model.count() > 0);
} }
...@@ -2246,7 +2244,7 @@ export class FocusOpenEditorsView extends Action { ...@@ -2246,7 +2244,7 @@ export class FocusOpenEditorsView extends Action {
} }
public run(): TPromise<any> { public run(): TPromise<any> {
return this.viewletService.openViewlet(Files.VIEWLET_ID, true).then((viewlet: ExplorerViewlet) => { return this.viewletService.openViewlet(VIEWLET_ID, true).then((viewlet: ExplorerViewlet) => {
viewlet.getOpenEditorsView().expand(); viewlet.getOpenEditorsView().expand();
viewlet.getOpenEditorsView().getViewer().DOMFocus(); viewlet.getOpenEditorsView().getViewer().DOMFocus();
}); });
...@@ -2267,7 +2265,7 @@ export class FocusFilesExplorer extends Action { ...@@ -2267,7 +2265,7 @@ export class FocusFilesExplorer extends Action {
} }
public run(): TPromise<any> { public run(): TPromise<any> {
return this.viewletService.openViewlet(Files.VIEWLET_ID, true).then((viewlet: ExplorerViewlet) => { return this.viewletService.openViewlet(VIEWLET_ID, true).then((viewlet: ExplorerViewlet) => {
const view = viewlet.getExplorerView(); const view = viewlet.getExplorerView();
if (view) { if (view) {
view.expand(); view.expand();
...@@ -2296,7 +2294,7 @@ export class ShowActiveFileInExplorer extends Action { ...@@ -2296,7 +2294,7 @@ export class ShowActiveFileInExplorer extends Action {
public run(): TPromise<any> { public run(): TPromise<any> {
let fileInput = asFileEditorInput(this.editorService.getActiveEditorInput(), true); let fileInput = asFileEditorInput(this.editorService.getActiveEditorInput(), true);
if (fileInput) { if (fileInput) {
return this.viewletService.openViewlet(Files.VIEWLET_ID, false).then((viewlet: ExplorerViewlet) => { return this.viewletService.openViewlet(VIEWLET_ID, false).then((viewlet: ExplorerViewlet) => {
const isInsideWorkspace = this.contextService.isInsideWorkspace(fileInput.getResource()); const isInsideWorkspace = this.contextService.isInsideWorkspace(fileInput.getResource());
if (isInsideWorkspace) { if (isInsideWorkspace) {
const explorerView = viewlet.getExplorerView(); const explorerView = viewlet.getExplorerView();
......
...@@ -11,8 +11,9 @@ import {ListenerUnbind} from 'vs/base/common/eventEmitter'; ...@@ -11,8 +11,9 @@ import {ListenerUnbind} from 'vs/base/common/eventEmitter';
import Event, {Emitter} from 'vs/base/common/event'; import Event, {Emitter} from 'vs/base/common/event';
import {FileEditorInput} from 'vs/workbench/parts/files/browser/editors/fileEditorInput'; import {FileEditorInput} from 'vs/workbench/parts/files/browser/editors/fileEditorInput';
import {CACHE, TextFileEditorModel} from 'vs/workbench/parts/files/common/editors/textFileEditorModel'; import {CACHE, TextFileEditorModel} from 'vs/workbench/parts/files/common/editors/textFileEditorModel';
import {IResult, ITextFileOperationResult, ConfirmResult, ITextFileService, IAutoSaveConfiguration, AutoSaveMode} from 'vs/workbench/parts/files/common/files'; import {IResult, ITextFileOperationResult, ITextFileService, IAutoSaveConfiguration, AutoSaveMode} from 'vs/workbench/parts/files/common/files';
import {EventType} from 'vs/workbench/common/events'; import {EventType} from 'vs/workbench/common/events';
import {ConfirmResult} from 'vs/workbench/common/editor';
import {WorkingFilesModel} from 'vs/workbench/parts/files/common/workingFilesModel'; import {WorkingFilesModel} from 'vs/workbench/parts/files/common/workingFilesModel';
import {IWorkspaceContextService} from 'vs/workbench/services/workspace/common/contextService'; import {IWorkspaceContextService} from 'vs/workbench/services/workspace/common/contextService';
import {IFilesConfiguration, IFileOperationResult, FileOperationResult, AutoSaveConfiguration} from 'vs/platform/files/common/files'; import {IFilesConfiguration, IFileOperationResult, FileOperationResult, AutoSaveConfiguration} from 'vs/platform/files/common/files';
......
...@@ -22,11 +22,11 @@ import {$} from 'vs/base/browser/builder'; ...@@ -22,11 +22,11 @@ import {$} from 'vs/base/browser/builder';
import platform = require('vs/base/common/platform'); import platform = require('vs/base/common/platform');
import glob = require('vs/base/common/glob'); import glob = require('vs/base/common/glob');
import {ContributableActionProvider} from 'vs/workbench/browser/actionBarRegistry'; import {ContributableActionProvider} from 'vs/workbench/browser/actionBarRegistry';
import {LocalFileChangeEvent, ConfirmResult, IFilesConfiguration, ITextFileService} from 'vs/workbench/parts/files/common/files'; import {LocalFileChangeEvent, IFilesConfiguration, ITextFileService} from 'vs/workbench/parts/files/common/files';
import {IFileOperationResult, FileOperationResult, IFileStat, IFileService} from 'vs/platform/files/common/files'; import {IFileOperationResult, FileOperationResult, IFileStat, IFileService} from 'vs/platform/files/common/files';
import {FileEditorInput} from 'vs/workbench/parts/files/browser/editors/fileEditorInput'; import {FileEditorInput} from 'vs/workbench/parts/files/browser/editors/fileEditorInput';
import {DuplicateFileAction, ImportFileAction, PasteFileAction, keybindingForAction, IEditableData, IFileViewletState} from 'vs/workbench/parts/files/browser/fileActions'; import {DuplicateFileAction, ImportFileAction, PasteFileAction, keybindingForAction, IEditableData, IFileViewletState} from 'vs/workbench/parts/files/browser/fileActions';
import {EditorOptions} from 'vs/workbench/common/editor'; import {EditorOptions, ConfirmResult} from 'vs/workbench/common/editor';
import {IDataSource, ITree, IElementCallback, IAccessibilityProvider, IRenderer, ContextMenuEvent, ISorter, IFilter, IDragAndDrop, IDragAndDropData, IDragOverReaction, DRAG_OVER_ACCEPT_BUBBLE_DOWN, DRAG_OVER_ACCEPT_BUBBLE_DOWN_COPY, DRAG_OVER_ACCEPT_BUBBLE_UP, DRAG_OVER_ACCEPT_BUBBLE_UP_COPY, DRAG_OVER_REJECT} from 'vs/base/parts/tree/browser/tree'; import {IDataSource, ITree, IElementCallback, IAccessibilityProvider, IRenderer, ContextMenuEvent, ISorter, IFilter, IDragAndDrop, IDragAndDropData, IDragOverReaction, DRAG_OVER_ACCEPT_BUBBLE_DOWN, DRAG_OVER_ACCEPT_BUBBLE_DOWN_COPY, DRAG_OVER_ACCEPT_BUBBLE_UP, DRAG_OVER_ACCEPT_BUBBLE_UP_COPY, DRAG_OVER_REJECT} from 'vs/base/parts/tree/browser/tree';
import labels = require('vs/base/common/labels'); import labels = require('vs/base/common/labels');
import {DesktopDragAndDropData, ExternalElementsDragAndDropData} from 'vs/base/parts/tree/browser/treeDnd'; import {DesktopDragAndDropData, ExternalElementsDragAndDropData} from 'vs/base/parts/tree/browser/treeDnd';
......
...@@ -11,7 +11,7 @@ import Event from 'vs/base/common/event'; ...@@ -11,7 +11,7 @@ import Event from 'vs/base/common/event';
import {guessMimeTypes} from 'vs/base/common/mime'; import {guessMimeTypes} from 'vs/base/common/mime';
import {IModel, IEditorOptions} from 'vs/editor/common/editorCommon'; import {IModel, IEditorOptions} from 'vs/editor/common/editorCommon';
import {IDisposable} from 'vs/base/common/lifecycle'; import {IDisposable} from 'vs/base/common/lifecycle';
import {EncodingMode, EditorInput, IFileEditorInput} from 'vs/workbench/common/editor'; import {EncodingMode, EditorInput, IFileEditorInput, ConfirmResult} from 'vs/workbench/common/editor';
import {IFileStat, IFilesConfiguration} from 'vs/platform/files/common/files'; import {IFileStat, IFilesConfiguration} from 'vs/platform/files/common/files';
import {createDecorator, ServiceIdentifier} from 'vs/platform/instantiation/common/instantiation'; import {createDecorator, ServiceIdentifier} from 'vs/platform/instantiation/common/instantiation';
import {FileStat} from 'vs/workbench/parts/files/common/explorerViewModel'; import {FileStat} from 'vs/workbench/parts/files/common/explorerViewModel';
...@@ -281,12 +281,6 @@ export class TextFileChangeEvent extends LocalFileChangeEvent { ...@@ -281,12 +281,6 @@ export class TextFileChangeEvent extends LocalFileChangeEvent {
export const TEXT_FILE_SERVICE_ID = 'textFileService'; export const TEXT_FILE_SERVICE_ID = 'textFileService';
export enum ConfirmResult {
SAVE,
DONT_SAVE,
CANCEL
}
export interface ITextFileOperationResult { export interface ITextFileOperationResult {
results: IResult[]; results: IResult[];
} }
......
...@@ -12,10 +12,11 @@ import strings = require('vs/base/common/strings'); ...@@ -12,10 +12,11 @@ import strings = require('vs/base/common/strings');
import {isWindows, isLinux} from 'vs/base/common/platform'; import {isWindows, isLinux} from 'vs/base/common/platform';
import URI from 'vs/base/common/uri'; import URI from 'vs/base/common/uri';
import {UntitledEditorModel} from 'vs/workbench/common/editor/untitledEditorModel'; import {UntitledEditorModel} from 'vs/workbench/common/editor/untitledEditorModel';
import {ConfirmResult} from 'vs/workbench/common/editor';
import {IEventService} from 'vs/platform/event/common/event'; import {IEventService} from 'vs/platform/event/common/event';
import {TextFileService as AbstractTextFileService} from 'vs/workbench/parts/files/browser/textFileServices'; import {TextFileService as AbstractTextFileService} from 'vs/workbench/parts/files/browser/textFileServices';
import {CACHE, TextFileEditorModel} from 'vs/workbench/parts/files/common/editors/textFileEditorModel'; import {CACHE, TextFileEditorModel} from 'vs/workbench/parts/files/common/editors/textFileEditorModel';
import {ITextFileOperationResult, ConfirmResult, AutoSaveMode} from 'vs/workbench/parts/files/common/files'; import {ITextFileOperationResult, AutoSaveMode} from 'vs/workbench/parts/files/common/files';
import {IUntitledEditorService} from 'vs/workbench/services/untitled/common/untitledEditorService'; import {IUntitledEditorService} from 'vs/workbench/services/untitled/common/untitledEditorService';
import {IFileService} from 'vs/platform/files/common/files'; import {IFileService} from 'vs/platform/files/common/files';
import {BinaryEditorModel} from 'vs/workbench/common/editor/binaryEditorModel'; import {BinaryEditorModel} from 'vs/workbench/common/editor/binaryEditorModel';
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册