openEditorsViewer.ts 20.8 KB
Newer Older
I
isidor 已提交
1 2 3 4 5
/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/

I
isidor 已提交
6
import nls = require('vs/nls');
I
isidor 已提交
7
import uri from 'vs/base/common/uri';
I
isidor 已提交
8
import errors = require('vs/base/common/errors');
9
import paths = require('vs/base/common/paths');
I
isidor 已提交
10
import {TPromise} from 'vs/base/common/winjs.base';
I
isidor 已提交
11
import {IAction} from 'vs/base/common/actions';
I
isidor 已提交
12
import treedefaults = require('vs/base/parts/tree/browser/treeDefaults');
I
isidor 已提交
13 14
import {IDataSource, ITree, IAccessibilityProvider, IDragAndDropData, IDragOverReaction, DRAG_OVER_ACCEPT, DRAG_OVER_REJECT, ContextMenuEvent, IRenderer} from 'vs/base/parts/tree/browser/tree';
import {ExternalElementsDragAndDropData, ElementsDragAndDropData, DesktopDragAndDropData} from 'vs/base/parts/tree/browser/treeDnd';
I
isidor 已提交
15
import {IActionProvider} from 'vs/base/parts/tree/browser/actionsRenderer';
16
import {IActionItem, ActionBar, Separator} from 'vs/base/browser/ui/actionbar/actionbar';
I
isidor 已提交
17
import {IKeyboardEvent} from 'vs/base/browser/keyboardEvent';
I
isidor 已提交
18
import dom = require('vs/base/browser/dom');
I
isidor 已提交
19
import {IMouseEvent, DragMouseEvent} from 'vs/base/browser/mouseEvent';
20
import {IResourceInput, IEditorInput} from 'vs/platform/editor/common/editor';
I
isidor 已提交
21
import {IInstantiationService} from 'vs/platform/instantiation/common/instantiation';
I
isidor 已提交
22
import {ITelemetryService} from 'vs/platform/telemetry/common/telemetry';
23
import {IEditorGroupService} from 'vs/workbench/services/group/common/groupService';
24
import {IContextMenuService} from 'vs/platform/contextview/browser/contextView';
25
import {IKeybindingService} from 'vs/platform/keybinding/common/keybindingService';
26
import {EditorOptions, UntitledEditorInput, IEditorGroup, IEditorStacksModel} from 'vs/workbench/common/editor';
I
isidor 已提交
27
import {ITextFileService, AutoSaveMode, FileEditorInput, asFileResource} from 'vs/workbench/parts/files/common/files';
I
isidor 已提交
28
import {IWorkbenchEditorService} from 'vs/workbench/services/editor/common/editorService';
29
import {EditorStacksModel, EditorGroup} from 'vs/workbench/common/editor/editorStacksModel';
I
isidor 已提交
30
import {keybindingForAction, SaveFileAction, RevertFileAction, SaveFileAsAction, OpenToSideAction, SelectResourceForCompareAction, CompareResourcesAction, SaveAllInGroupAction} from 'vs/workbench/parts/files/browser/fileActions';
31 32
import {CopyPathAction, RevealInOSAction} from 'vs/workbench/parts/files/electron-browser/electronFileActions';
import {OpenConsoleAction} from 'vs/workbench/parts/execution/electron-browser/terminal.contribution';
I
isidor 已提交
33
import {IUntitledEditorService} from 'vs/workbench/services/untitled/common/untitledEditorService';
B
Benjamin Pasero 已提交
34
import {CloseOtherEditorsInGroupAction, CloseEditorAction, CloseEditorsInGroupAction} from 'vs/workbench/browser/parts/editor/editorActions';
I
isidor 已提交
35

I
isidor 已提交
36 37
const $ = dom.emmet;

I
isidor 已提交
38 39
export class OpenEditor {

40
	constructor(private editor: IEditorInput, private group: IEditorGroup) {
I
isidor 已提交
41 42 43 44 45 46 47 48 49 50 51 52
		// noop
	}

	public get editorInput() {
		return this.editor;
	}

	public get editorGroup() {
		return this.group;
	}

	public getId(): string {
53
		return `openeditor:${this.group.id}:${this.group.indexOf(this.editor)}:${this.editor.getName()}:${this.editor.getDescription()}`;
I
isidor 已提交
54 55 56 57 58 59 60 61 62 63
	}

	public isPreview(): boolean {
		return this.group.isPreview(this.editor);
	}

	public isUntitled(): boolean {
		return this.editor instanceof UntitledEditorInput;
	}

B
Benjamin Pasero 已提交
64 65
	public isDirty(): boolean {
		return this.editor.isDirty();
I
isidor 已提交
66 67 68 69 70 71 72 73 74 75 76 77 78
	}

	public getResource(): uri {
		if (this.editor instanceof FileEditorInput) {
			return (<FileEditorInput>this.editor).getResource();
		} else if (this.editor instanceof UntitledEditorInput) {
			return (<UntitledEditorInput>this.editor).getResource();
		}

		return null;
	}
}

I
isidor 已提交
79
export class DataSource implements IDataSource {
I
isidor 已提交
80

I
isidor 已提交
81
	public getId(tree: ITree, element: any): string {
I
isidor 已提交
82 83 84 85 86 87 88
		if (element instanceof EditorStacksModel) {
			return 'root';
		}
		if (element instanceof EditorGroup) {
			return (<IEditorGroup>element).id.toString();
		}

89
		return (<OpenEditor>element).getId();
I
isidor 已提交
90 91
	}

I
isidor 已提交
92
	public hasChildren(tree: ITree, element: any): boolean {
I
isidor 已提交
93
		return element instanceof EditorStacksModel || element instanceof EditorGroup;
I
isidor 已提交
94 95
	}

I
isidor 已提交
96
	public getChildren(tree: ITree, element: any): TPromise<any> {
I
isidor 已提交
97 98 99 100
		if (element instanceof EditorStacksModel) {
			return TPromise.as((<IEditorStacksModel>element).groups);
		}

101 102
		const editorGroup = <IEditorGroup>element;
		return TPromise.as(editorGroup.getEditors().map(ei => new OpenEditor(ei, editorGroup)));
I
isidor 已提交
103 104
	}

I
isidor 已提交
105
	public getParent(tree: ITree, element: any): TPromise<any> {
I
isidor 已提交
106 107 108 109
		return TPromise.as(null);
	}
}

110
interface IOpenEditorTemplateData {
111
	container: HTMLElement;
I
isidor 已提交
112
	root: HTMLElement;
I
isidor 已提交
113 114
	name: HTMLSpanElement;
	description: HTMLSpanElement;
I
isidor 已提交
115
	actionBar: ActionBar;
I
isidor 已提交
116 117 118 119
}

interface IEditorGroupTemplateData {
	root: HTMLElement;
120 121
	name: HTMLSpanElement;
	actionBar: ActionBar;
I
isidor 已提交
122 123
}

I
isidor 已提交
124
export class Renderer implements IRenderer {
I
isidor 已提交
125

I
isidor 已提交
126
	public static ITEM_HEIGHT = 22;
I
isidor 已提交
127 128
	private static EDITOR_GROUP_TEMPLATE_ID = 'editorgroup';
	private static OPEN_EDITOR_TEMPLATE_ID = 'openeditor';
I
isidor 已提交
129

I
isidor 已提交
130
	constructor(private actionProvider: ActionProvider, private model: IEditorStacksModel,
I
isidor 已提交
131 132 133
		@ITextFileService private textFileService: ITextFileService,
		@IUntitledEditorService private untitledEditorService: IUntitledEditorService
	) {
I
isidor 已提交
134 135 136
		// noop
	}

I
isidor 已提交
137
	public getHeight(tree: ITree, element: any): number {
I
isidor 已提交
138 139 140
		return Renderer.ITEM_HEIGHT;
	}

I
isidor 已提交
141
	public getTemplateId(tree: ITree, element: any): string {
I
isidor 已提交
142 143 144 145 146
		if (element instanceof EditorGroup) {
			return Renderer.EDITOR_GROUP_TEMPLATE_ID;
		}

		return Renderer.OPEN_EDITOR_TEMPLATE_ID;
I
isidor 已提交
147 148
	}

I
isidor 已提交
149
	public renderTemplate(tree: ITree, templateId: string, container: HTMLElement): any {
I
isidor 已提交
150 151 152
		if (templateId === Renderer.EDITOR_GROUP_TEMPLATE_ID) {
			const editorGroupTemplate: IEditorGroupTemplateData = Object.create(null);
			editorGroupTemplate.root = dom.append(container, $('.editor-group'));
153 154 155
			editorGroupTemplate.name = dom.append(editorGroupTemplate.root, $('span.name'));
			editorGroupTemplate.actionBar = new ActionBar(container);
			editorGroupTemplate.actionBar.push(this.actionProvider.getEditorGroupActions(), { icon: true, label: false});
I
isidor 已提交
156

I
isidor 已提交
157 158 159
			return editorGroupTemplate;
		}

160
		const editorTemplate: IOpenEditorTemplateData = Object.create(null);
161
		editorTemplate.container = container;
I
isidor 已提交
162 163 164
		editorTemplate.actionBar = new ActionBar(container);
		editorTemplate.actionBar.push(this.actionProvider.getOpenEditorActions(), { icon: true, label: false});

I
isidor 已提交
165
		editorTemplate.root = dom.append(container, $('.open-editor'));
I
isidor 已提交
166 167
		editorTemplate.name = dom.append(editorTemplate.root, $('span.name'));
		editorTemplate.description = dom.append(editorTemplate.root, $('span.description'));
I
isidor 已提交
168

I
isidor 已提交
169

I
isidor 已提交
170
		return editorTemplate;
I
isidor 已提交
171 172
	}

I
isidor 已提交
173
	public renderElement(tree: ITree, element: any, templateId: string, templateData: any): void {
I
isidor 已提交
174 175 176 177 178 179 180
		if (templateId === Renderer.EDITOR_GROUP_TEMPLATE_ID) {
			this.renderEditorGroup(tree, element, templateData);
		} else {
			this.renderOpenEditor(tree, element, templateData);
		}
	}

I
isidor 已提交
181
	private renderEditorGroup(tree: ITree, editorGroup: IEditorGroup, templateData: IOpenEditorTemplateData): void {
182
		templateData.name.textContent = editorGroup.label;
I
isidor 已提交
183
		templateData.actionBar.context = { group: editorGroup };
I
isidor 已提交
184 185
	}

I
isidor 已提交
186
	private renderOpenEditor(tree: ITree, editor: OpenEditor, templateData: IOpenEditorTemplateData): void {
I
isidor 已提交
187
		editor.isPreview() ? dom.addClass(templateData.root, 'preview') : dom.removeClass(templateData.root, 'preview');
B
Benjamin Pasero 已提交
188
		editor.isDirty() ? dom.addClass(templateData.container, 'dirty') : dom.removeClass(templateData.container, 'dirty');
189 190
		const resource = editor.getResource();
		templateData.root.title = resource ? resource.fsPath : '';
191 192
		templateData.name.textContent = editor.editorInput.getName();
		templateData.description.textContent = editor.editorInput.getDescription();
I
isidor 已提交
193
		templateData.actionBar.context = { group: editor.editorGroup, editor: editor.editorInput };
I
isidor 已提交
194 195
	}

I
isidor 已提交
196
	public disposeTemplate(tree: ITree, templateId: string, templateData: any): void {
I
isidor 已提交
197 198 199
		if (templateId === Renderer.OPEN_EDITOR_TEMPLATE_ID) {
			(<IOpenEditorTemplateData>templateData).actionBar.dispose();
		}
200 201 202
		if (templateId === Renderer.EDITOR_GROUP_TEMPLATE_ID) {
			(<IEditorGroupTemplateData>templateData).actionBar.dispose();
		}
I
isidor 已提交
203
	}
I
isidor 已提交
204
}
I
isidor 已提交
205 206 207

export class Controller extends treedefaults.DefaultController {

I
isidor 已提交
208 209
	constructor(private actionProvider: ActionProvider, private model: IEditorStacksModel,
		@IWorkbenchEditorService private editorService: IWorkbenchEditorService,
210
		@IEditorGroupService private editorGroupService: IEditorGroupService,
I
isidor 已提交
211 212
		@IInstantiationService private instantiationService: IInstantiationService,
		@IContextMenuService private contextMenuService: IContextMenuService,
213 214
		@ITelemetryService private telemetryService: ITelemetryService,
		@IKeybindingService private keybindingService: IKeybindingService
I
isidor 已提交
215 216 217 218
	) {
		super({ clickBehavior: treedefaults.ClickBehavior.ON_MOUSE_DOWN });
	}

219 220 221 222
	public onClick(tree: ITree, element: any, event: IMouseEvent): boolean {

		// Close opened editor on middle mouse click
		if (element instanceof OpenEditor && event.browserEvent && event.browserEvent.button === 1 /* Middle Button */) {
B
Benjamin Pasero 已提交
223 224 225
			const position = this.model.positionOfGroup(element.editorGroup);

			this.editorService.closeEditor(position, element.editorInput).done(null, errors.onUnexpectedError);
226 227 228 229 230 231 232

			return true;
		}

		return super.onClick(tree, element, event);
	}

I
isidor 已提交
233
	protected onLeftClick(tree: ITree, element: any, event: IMouseEvent, origin: string = 'mouse'): boolean {
I
isidor 已提交
234 235
		const payload = { origin: origin };
		const isDoubleClick = (origin === 'mouse' && event.detail === 2);
I
isidor 已提交
236

I
isidor 已提交
237 238 239 240 241 242 243
		// Cancel Event
		const isMouseDown = event && event.browserEvent && event.browserEvent.type === 'mousedown';
		if (!isMouseDown) {
			event.preventDefault(); // we cannot preventDefault onMouseDown because this would break DND otherwise
		}
		event.stopPropagation();

244 245 246 247 248
		// Status group should never get selected nor expanded/collapsed
		if (!(element instanceof OpenEditor)) {
			return true;
		}

I
isidor 已提交
249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268
		// Set DOM focus
		tree.DOMFocus();

		// Allow to unselect
		if (event.shiftKey) {
			const selection = tree.getSelection();
			if (selection && selection.length > 0 && selection[0] === element) {
				tree.clearSelection(payload);
			}
		}

		// Select, Focus and open files
		else {
			tree.setFocus(element, payload);

			if (isDoubleClick) {
				event.preventDefault(); // focus moves to editor, we need to prevent default
			}

			tree.setSelection([element], payload);
269
			this.openEditor(element, isDoubleClick);
I
isidor 已提交
270 271 272
		}

		return true;
I
isidor 已提交
273 274
	}

275 276 277 278 279 280 281 282 283
	// Do not allow left / right to expand and collapse groups #7848
	protected onLeft(tree: ITree, event: IKeyboardEvent): boolean {
		return true;
	}

	protected onRight(tree: ITree, event: IKeyboardEvent): boolean {
		return true;
	}

I
isidor 已提交
284
	protected onEnter(tree: ITree, event: IKeyboardEvent): boolean {
I
isidor 已提交
285 286 287 288 289 290 291 292 293 294
		var element = tree.getFocus();

		// Editor groups should never get selected nor expanded/collapsed
		if (element instanceof EditorGroup) {
			event.preventDefault();
			event.stopPropagation();

			return true;
		}

I
isidor 已提交
295
		this.openEditor(element, false);
I
isidor 已提交
296

I
isidor 已提交
297 298
		return super.onEnter(tree, event);
	}
I
isidor 已提交
299

I
isidor 已提交
300
	public onContextMenu(tree: ITree, element: any, event: ContextMenuEvent): boolean {
I
isidor 已提交
301 302 303
		if (event.target && event.target.tagName && event.target.tagName.toLowerCase() === 'input') {
			return false;
		}
304 305
		// Check if clicked on some element
		if (element === tree.getInput()) {
I
isidor 已提交
306 307 308 309 310 311 312
			return false;
		}

		event.preventDefault();
		event.stopPropagation();

		tree.setFocus(element);
I
isidor 已提交
313 314
		const group = element instanceof EditorGroup ? element : (<OpenEditor>element).editorGroup;
		const editor = element instanceof OpenEditor ? (<OpenEditor>element).editorInput : undefined;
I
isidor 已提交
315 316 317 318 319

		let anchor = { x: event.posx + 1, y: event.posy };
		this.contextMenuService.showContextMenu({
			getAnchor: () => anchor,
			getActions: () => this.actionProvider.getSecondaryActions(tree, element),
320 321 322 323 324 325 326 327
			getKeyBinding: (action) => {
				const opts = this.keybindingService.lookupKeybindings(action.id);
				if (opts.length > 0) {
					return opts[0]; // only take the first one
				}

				return keybindingForAction(action.id);
			},
I
isidor 已提交
328 329 330 331 332
			onHide: (wasCancelled?: boolean) => {
				if (wasCancelled) {
					tree.DOMFocus();
				}
			},
I
isidor 已提交
333
			getActionsContext: () => ({ group, editor })
I
isidor 已提交
334 335 336 337 338
		});

		return true;
	}

339
	private openEditor(element: OpenEditor, pinEditor: boolean): void {
I
isidor 已提交
340 341 342
		if (element) {
			this.telemetryService.publicLog('workbenchActionExecuted', { id: 'workbench.files.openFile', from: 'openEditors' });
			const position = this.model.positionOfGroup(element.editorGroup);
343
			if (pinEditor) {
344
				this.editorGroupService.pinEditor(position, element.editorInput);
345
			}
346
			this.editorGroupService.activateGroup(position);
347
			this.editorService.openEditor(element.editorInput, EditorOptions.create({ preserveFocus: !pinEditor }), position)
348
				.done(() => this.editorGroupService.activateGroup(position), errors.onUnexpectedError);
I
isidor 已提交
349 350
		}
	}
I
isidor 已提交
351
}
I
isidor 已提交
352

I
isidor 已提交
353
export class AccessibilityProvider implements IAccessibilityProvider {
I
isidor 已提交
354

I
isidor 已提交
355
	getAriaLabel(tree: ITree, element: any): string {
I
isidor 已提交
356 357 358 359
		if (element instanceof EditorGroup) {
			return nls.localize('editorGroupAriaLabel', "{0}, Editor Group", (<EditorGroup>element).label);
		}

360
		return nls.localize('openEditorAriaLabel', "{0}, Open Editor", (<OpenEditor>element).editorInput.getName());
I
isidor 已提交
361 362
	}
}
I
isidor 已提交
363 364 365

export class ActionProvider implements IActionProvider {

366
	constructor(
367
		private model: IEditorStacksModel,
368 369 370 371
		@IInstantiationService private instantiationService: IInstantiationService,
		@ITextFileService private textFileService: ITextFileService,
		@IUntitledEditorService private untitledEditorService: IUntitledEditorService
	) {
I
isidor 已提交
372 373 374
		// noop
	}

I
isidor 已提交
375
	public hasActions(tree: ITree, element: any): boolean {
376 377
		const multipleGroups = this.model.groups.length > 1;
		return element instanceof OpenEditor || (element instanceof EditorGroup && multipleGroups);
I
isidor 已提交
378 379
	}

I
isidor 已提交
380
	public getActions(tree: ITree, element: any): TPromise<IAction[]> {
I
isidor 已提交
381 382 383
		if (element instanceof OpenEditor) {
			return TPromise.as(this.getOpenEditorActions());
		}
384 385 386
		if (element instanceof EditorGroup) {
			return TPromise.as(this.getEditorGroupActions());
		}
I
isidor 已提交
387

I
isidor 已提交
388 389 390
		return TPromise.as([]);
	}

I
isidor 已提交
391
	public getOpenEditorActions(): IAction[] {
I
isidor 已提交
392
		return [this.instantiationService.createInstance(CloseEditorAction, CloseEditorAction.ID, CloseEditorAction.LABEL)];
I
isidor 已提交
393 394
	}

395
	public getEditorGroupActions(): IAction[] {
I
isidor 已提交
396 397
		const saveAllAction = this.instantiationService.createInstance(SaveAllInGroupAction, SaveAllInGroupAction.ID, SaveAllInGroupAction.LABEL);

398 399
		return [
			saveAllAction,
B
Benjamin Pasero 已提交
400
			this.instantiationService.createInstance(CloseEditorsInGroupAction, CloseEditorsInGroupAction.ID, CloseEditorsInGroupAction.LABEL)
401 402 403
		];
	}

I
isidor 已提交
404
	public hasSecondaryActions(tree: ITree, element: any): boolean {
405
		return element instanceof OpenEditor || element instanceof EditorGroup;
I
isidor 已提交
406 407
	}

I
isidor 已提交
408
	public getSecondaryActions(tree: ITree, element: any): TPromise<IAction[]> {
409
		const result = [];
B
Benjamin Pasero 已提交
410
		const autoSaveEnabled = this.textFileService.getAutoSaveMode() === AutoSaveMode.AFTER_SHORT_DELAY;
411

412
		if (element instanceof EditorGroup) {
I
isidor 已提交
413
			if (!autoSaveEnabled) {
414
				result.push(this.instantiationService.createInstance(SaveAllInGroupAction, SaveAllInGroupAction.ID, nls.localize('saveAll', "Save All")));
I
isidor 已提交
415 416 417
				result.push(new Separator());
			}

B
Benjamin Pasero 已提交
418
			result.push(this.instantiationService.createInstance(CloseEditorsInGroupAction, CloseEditorsInGroupAction.ID, nls.localize('closeAll', "Close All")));
419
		} else {
420 421 422 423 424 425
			const openEditor = <OpenEditor>element;
			const resource = openEditor.getResource();
			if (resource) {
				// Open to side
				result.push(this.instantiationService.createInstance(OpenToSideAction, tree, resource, false));

426
				if (!openEditor.isUntitled()) {
427 428
					result.push(new Separator());

429 430 431 432 433 434 435
					result.push(this.instantiationService.createInstance(RevealInOSAction, resource));
					const openConsoleAction = this.instantiationService.createInstance(OpenConsoleAction, OpenConsoleAction.ID, OpenConsoleAction.ScopedLabel);
					openConsoleAction.setResource(uri.file(paths.dirname(resource.fsPath)));
					result.push(openConsoleAction);
					result.push(this.instantiationService.createInstance(CopyPathAction, resource));

					// Files: Save / Revert
436
					if (!autoSaveEnabled) {
437 438 439 440
						result.push(new Separator());

						const saveAction = this.instantiationService.createInstance(SaveFileAction, SaveFileAction.ID, SaveFileAction.LABEL);
						saveAction.setResource(resource);
441
						saveAction.enabled = openEditor.isDirty();
442 443 444 445
						result.push(saveAction);

						const revertAction = this.instantiationService.createInstance(RevertFileAction, RevertFileAction.ID, RevertFileAction.LABEL);
						revertAction.setResource(resource);
B
Benjamin Pasero 已提交
446
						revertAction.enabled = openEditor.isDirty();
447 448
						result.push(revertAction);
					}
449

450
					result.push(new Separator());
451

452 453 454 455 456 457 458
					// Compare Actions
					const runCompareAction = this.instantiationService.createInstance(CompareResourcesAction, resource, tree);
					if (runCompareAction._isEnabled()) {
						result.push(runCompareAction);
					}
					result.push(this.instantiationService.createInstance(SelectResourceForCompareAction, resource, tree));
				}
459
				// Untitled: Save / Save As
460
				else {
461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476
					result.push(new Separator());

					if (this.untitledEditorService.hasAssociatedFilePath(resource)) {
						let saveUntitledAction = this.instantiationService.createInstance(SaveFileAction, SaveFileAction.ID, SaveFileAction.LABEL);
						saveUntitledAction.setResource(resource);
						result.push(saveUntitledAction);
					}

					let saveAsAction = this.instantiationService.createInstance(SaveFileAsAction, SaveFileAsAction.ID, SaveFileAsAction.LABEL);
					saveAsAction.setResource(resource);
					result.push(saveAsAction);
				}

				result.push(new Separator());
			}

477 478
			result.push(this.instantiationService.createInstance(CloseEditorAction, CloseEditorAction.ID, nls.localize('close', "Close")));
			const closeOtherEditorsInGroupAction = this.instantiationService.createInstance(CloseOtherEditorsInGroupAction, CloseOtherEditorsInGroupAction.ID, nls.localize('closeOthers', "Close Others"));
479
			closeOtherEditorsInGroupAction.enabled = openEditor.editorGroup.count > 1;
480
			result.push(closeOtherEditorsInGroupAction);
B
Benjamin Pasero 已提交
481
			result.push(this.instantiationService.createInstance(CloseEditorsInGroupAction, CloseEditorsInGroupAction.ID, nls.localize('closeAll', "Close All")));
482 483 484
		}

		return TPromise.as(result);
I
isidor 已提交
485 486
	}

I
isidor 已提交
487
	public getActionItem(tree: ITree, element: any, action: IAction): IActionItem {
I
isidor 已提交
488 489 490
		return null;
	}
}
I
isidor 已提交
491 492 493

export class DragAndDrop extends treedefaults.DefaultDragAndDrop {

494 495 496 497
	constructor(
		@IWorkbenchEditorService private editorService: IWorkbenchEditorService,
		@IEditorGroupService private editorGroupService: IEditorGroupService
	) {
I
isidor 已提交
498 499 500 501
		super();
	}

	public getDragURI(tree: ITree, element: OpenEditor): string {
502 503 504 505 506
		if (!(element instanceof OpenEditor)) {
			return null;
		}

		const resource = element.getResource();
507
		// Some open editors do not have a resource so use the name as drag identifier instead #7021
508
		return resource ? resource.toString() : element.editorInput.getName();
I
isidor 已提交
509 510
	}

I
isidor 已提交
511 512
	public onDragOver(tree: ITree, data: IDragAndDropData, target: OpenEditor|EditorGroup, originalEvent: DragMouseEvent): IDragOverReaction {
		if (!(target instanceof OpenEditor) && !(target instanceof EditorGroup)) {
I
isidor 已提交
513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533
			return DRAG_OVER_REJECT;
		}

		if (data instanceof ExternalElementsDragAndDropData) {
			let resource = asFileResource(data.getData()[0]);

			if (!resource) {
				return DRAG_OVER_REJECT;
			}

			return resource.isDirectory ? DRAG_OVER_REJECT : DRAG_OVER_ACCEPT;
		}

		if (data instanceof DesktopDragAndDropData) {
			return DRAG_OVER_REJECT;
		}

		if (!(data instanceof ElementsDragAndDropData)) {
			return DRAG_OVER_REJECT;
		}

I
isidor 已提交
534
		return DRAG_OVER_ACCEPT;
I
isidor 已提交
535 536
	}

I
isidor 已提交
537 538
	public drop(tree: ITree, data: IDragAndDropData, target: OpenEditor|EditorGroup, originalEvent: DragMouseEvent): void {
		let draggedElement: OpenEditor|EditorGroup;
539
		const model = this.editorGroupService.getStacksModel();
I
isidor 已提交
540
		const positionOfTargetGroup =  model.positionOfGroup(target instanceof EditorGroup ? target : target.editorGroup);
541
		const index = target instanceof OpenEditor ? target.editorGroup.indexOf(target.editorInput) : undefined;
I
isidor 已提交
542 543
		// Support drop from explorer viewer
		if (data instanceof ExternalElementsDragAndDropData) {
544
			let resource = <IResourceInput>asFileResource(data.getData()[0]);
B
Benjamin Pasero 已提交
545
			resource.options = { index, pinned: true };
I
isidor 已提交
546
			this.editorService.openEditor(resource, positionOfTargetGroup).done(null, errors.onUnexpectedError);
I
isidor 已提交
547 548 549 550
		}

		// Drop within viewer
		else {
I
isidor 已提交
551
			let source: OpenEditor|EditorGroup[] = data.getData();
I
isidor 已提交
552 553 554 555 556 557
			if (Array.isArray(source)) {
				draggedElement = source[0];
			}
		}

		if (draggedElement) {
I
isidor 已提交
558
			if (draggedElement instanceof OpenEditor) {
559
				this.editorGroupService.moveEditor(draggedElement.editorInput, model.positionOfGroup(draggedElement.editorGroup), positionOfTargetGroup, index);
I
isidor 已提交
560
			} else {
561
				this.editorGroupService.moveGroup(model.positionOfGroup(draggedElement), positionOfTargetGroup);
I
isidor 已提交
562
			}
I
isidor 已提交
563 564 565
		}
	}
}