Skip to content

Commit e52abf6

Browse files
authored
Implement basic SCM DnD (microsoft#181463)
1 parent 4981453 commit e52abf6

File tree

1 file changed

+59
-1
lines changed

1 file changed

+59
-1
lines changed

src/vs/workbench/contrib/scm/browser/scmViewPane.ts

Lines changed: 59 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ import { isSCMResource, isSCMResourceGroup, connectPrimaryMenuToInlineActionBar,
2727
import { WorkbenchCompressibleObjectTree, IOpenEvent } from 'vs/platform/list/browser/listService';
2828
import { IConfigurationService, ConfigurationTarget, IConfigurationChangeEvent } from 'vs/platform/configuration/common/configuration';
2929
import { disposableTimeout, ThrottledDelayer } from 'vs/base/common/async';
30-
import { ITreeNode, ITreeFilter, ITreeSorter, ITreeContextMenuEvent } from 'vs/base/browser/ui/tree/tree';
30+
import { ITreeNode, ITreeFilter, ITreeSorter, ITreeContextMenuEvent, ITreeDragAndDrop, ITreeDragOverReaction } from 'vs/base/browser/ui/tree/tree';
3131
import { ResourceTree, IResourceNode } from 'vs/base/common/resourceTree';
3232
import { ISplice } from 'vs/base/common/sequence';
3333
import { ICompressibleTreeRenderer, ICompressibleKeyboardNavigationLabelProvider } from 'vs/base/browser/ui/tree/objectTree';
@@ -92,6 +92,10 @@ import { InlineCompletionsController } from 'vs/editor/contrib/inlineCompletions
9292
import { CodeActionController } from 'vs/editor/contrib/codeAction/browser/codeActionController';
9393
import { IResolvedTextEditorModel, ITextModelContentProvider, ITextModelService } from 'vs/editor/common/services/resolverService';
9494
import { Schemas } from 'vs/base/common/network';
95+
import { IDragAndDropData } from 'vs/base/browser/dnd';
96+
import { fillEditorsDragData } from 'vs/workbench/browser/dnd';
97+
import { ElementsDragAndDropData } from 'vs/base/browser/ui/list/listView';
98+
import { CodeDataTransfers } from 'vs/platform/dnd/browser/dnd';
9599

96100
type TreeElement = ISCMRepository | ISCMInput | ISCMActionButton | ISCMResourceGroup | IResourceNode<ISCMResource, ISCMResourceGroup> | ISCMResource;
97101

@@ -166,6 +170,58 @@ class ActionButtonRenderer implements ICompressibleTreeRenderer<ISCMActionButton
166170
}
167171
}
168172

173+
174+
class SCMTreeDragAndDrop implements ITreeDragAndDrop<TreeElement> {
175+
constructor(private readonly instantiationService: IInstantiationService) { }
176+
177+
getDragURI(element: TreeElement): string | null {
178+
if (isSCMResource(element)) {
179+
return element.sourceUri.toString();
180+
}
181+
182+
return null;
183+
}
184+
185+
onDragStart(data: IDragAndDropData, originalEvent: DragEvent): void {
186+
const items = SCMTreeDragAndDrop.getResourcesFromDragAndDropData(data as ElementsDragAndDropData<TreeElement, TreeElement[]>);
187+
if (originalEvent.dataTransfer && items?.length) {
188+
this.instantiationService.invokeFunction(accessor => fillEditorsDragData(accessor, items, originalEvent));
189+
190+
const fileResources = items.filter(s => s.scheme === Schemas.file).map(r => r.fsPath);
191+
if (fileResources.length) {
192+
originalEvent.dataTransfer.setData(CodeDataTransfers.FILES, JSON.stringify(fileResources));
193+
}
194+
}
195+
}
196+
197+
getDragLabel(elements: TreeElement[], originalEvent: DragEvent): string | undefined {
198+
if (elements.length === 1) {
199+
const element = elements[0];
200+
if (isSCMResource(element)) {
201+
return basename(element.sourceUri);
202+
}
203+
}
204+
205+
return String(elements.length);
206+
}
207+
208+
onDragOver(data: IDragAndDropData, targetElement: TreeElement | undefined, targetIndex: number | undefined, originalEvent: DragEvent): boolean | ITreeDragOverReaction {
209+
return true;
210+
}
211+
212+
drop(data: IDragAndDropData, targetElement: TreeElement | undefined, targetIndex: number | undefined, originalEvent: DragEvent): void { }
213+
214+
private static getResourcesFromDragAndDropData(data: ElementsDragAndDropData<TreeElement, TreeElement[]>): URI[] {
215+
const uris: URI[] = [];
216+
for (const element of [...data.context ?? [], ...data.elements]) {
217+
if (isSCMResource(element)) {
218+
uris.push(element.sourceUri);
219+
}
220+
}
221+
return uris;
222+
}
223+
}
224+
169225
interface InputTemplate {
170226
readonly inputWidget: SCMInputWidget;
171227
readonly elementDisposables: DisposableStore;
@@ -2307,6 +2363,7 @@ export class SCMViewPane extends ViewPane {
23072363
const sorter = new SCMTreeSorter(() => this._viewModel);
23082364
const keyboardNavigationLabelProvider = this.instantiationService.createInstance(SCMTreeKeyboardNavigationLabelProvider, () => this._viewModel);
23092365
const identityProvider = new SCMResourceIdentityProvider();
2366+
const dnd = new SCMTreeDragAndDrop(this.instantiationService);
23102367

23112368
this.tree = this.instantiationService.createInstance(
23122369
WorkbenchCompressibleObjectTree,
@@ -2317,6 +2374,7 @@ export class SCMViewPane extends ViewPane {
23172374
{
23182375
transformOptimization: false,
23192376
identityProvider,
2377+
dnd,
23202378
horizontalScrolling: false,
23212379
setRowLineHeight: false,
23222380
filter,

0 commit comments

Comments
 (0)