Skip to content

Commit d891b49

Browse files
authored
Enable file DataTransfer on tree views (microsoft#150328)
For microsoft#147481
1 parent 61861d7 commit d891b49

File tree

6 files changed

+35
-44
lines changed

6 files changed

+35
-44
lines changed

src/vs/workbench/api/browser/mainThreadTreeViews.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,14 +37,14 @@ export class MainThreadTreeViews extends Disposable implements MainThreadTreeVie
3737
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostTreeViews);
3838
}
3939

40-
async $registerTreeViewDataProvider(treeViewId: string, options: { showCollapseAll: boolean; canSelectMany: boolean; dropMimeTypes: string[]; dragMimeTypes: string[]; hasHandleDrag: boolean; hasHandleDrop: boolean }): Promise<void> {
40+
async $registerTreeViewDataProvider(treeViewId: string, options: { showCollapseAll: boolean; canSelectMany: boolean; dropMimeTypes: string[]; dragMimeTypes: string[]; hasHandleDrag: boolean; hasHandleDrop: boolean; supportsFileDataTransfers: boolean }): Promise<void> {
4141
this.logService.trace('MainThreadTreeViews#$registerTreeViewDataProvider', treeViewId, options);
4242

4343
this.extensionService.whenInstalledExtensionsRegistered().then(() => {
4444
const dataProvider = new TreeViewDataProvider(treeViewId, this._proxy, this.notificationService);
4545
this._dataProviders.set(treeViewId, dataProvider);
4646
const dndController = (options.hasHandleDrag || options.hasHandleDrop)
47-
? new TreeViewDragAndDropController(treeViewId, options.dropMimeTypes, options.dragMimeTypes, options.hasHandleDrag, this._proxy) : undefined;
47+
? new TreeViewDragAndDropController(treeViewId, options.dropMimeTypes, options.dragMimeTypes, options.hasHandleDrag, options.supportsFileDataTransfers, this._proxy) : undefined;
4848
const viewer = this.getTreeView(treeViewId);
4949
if (viewer) {
5050
// Order is important here. The internal tree isn't created until the dataProvider is set.
@@ -201,6 +201,7 @@ class TreeViewDragAndDropController implements ITreeViewDragAndDropController {
201201
readonly dropMimeTypes: string[],
202202
readonly dragMimeTypes: string[],
203203
readonly hasWillDrop: boolean,
204+
readonly supportsFileDataTransfers: boolean,
204205
private readonly _proxy: ExtHostTreeViewsShape) { }
205206

206207
async handleDrop(dataTransfer: VSDataTransfer, targetTreeItem: ITreeItem | undefined, token: CancellationToken,

src/vs/workbench/api/common/extHost.protocol.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -258,7 +258,7 @@ export interface MainThreadTextEditorsShape extends IDisposable {
258258
}
259259

260260
export interface MainThreadTreeViewsShape extends IDisposable {
261-
$registerTreeViewDataProvider(treeViewId: string, options: { showCollapseAll: boolean; canSelectMany: boolean; dropMimeTypes: readonly string[]; dragMimeTypes: readonly string[]; hasHandleDrag: boolean; hasHandleDrop: boolean }): Promise<void>;
261+
$registerTreeViewDataProvider(treeViewId: string, options: { showCollapseAll: boolean; canSelectMany: boolean; dropMimeTypes: readonly string[]; dragMimeTypes: readonly string[]; hasHandleDrag: boolean; hasHandleDrop: boolean; supportsFileDataTransfers: boolean }): Promise<void>;
262262
$refresh(treeViewId: string, itemsToRefresh?: { [treeItemHandle: string]: ITreeItem }): Promise<void>;
263263
$reveal(treeViewId: string, itemInfo: { item: ITreeItem; parentChain: ITreeItem[] } | undefined, options: IRevealOptions): Promise<void>;
264264
$setMessage(treeViewId: string, message: string): void;

src/vs/workbench/api/common/extHostTreeViews.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ import { IMarkdownString } from 'vs/base/common/htmlContent';
2424
import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation';
2525
import { Command } from 'vs/editor/common/languages';
2626
import { ITreeViewsService, TreeviewsService } from 'vs/workbench/services/views/common/treeViewsService';
27-
import { checkProposedApiEnabled } from 'vs/workbench/services/extensions/common/extensions';
27+
import { checkProposedApiEnabled, isProposedApiEnabled } from 'vs/workbench/services/extensions/common/extensions';
2828

2929
type TreeItemHandle = string;
3030

@@ -92,7 +92,8 @@ export class ExtHostTreeViews implements ExtHostTreeViewsShape {
9292
const dragMimeTypes = options.dragAndDropController?.dragMimeTypes ?? [];
9393
const hasHandleDrag = !!options.dragAndDropController?.handleDrag;
9494
const hasHandleDrop = !!options.dragAndDropController?.handleDrop;
95-
const registerPromise = this._proxy.$registerTreeViewDataProvider(viewId, { showCollapseAll: !!options.showCollapseAll, canSelectMany: !!options.canSelectMany, dropMimeTypes, dragMimeTypes, hasHandleDrag, hasHandleDrop });
95+
const supportsFileDataTransfers = isProposedApiEnabled(extension, 'dataTransferFiles');
96+
const registerPromise = this._proxy.$registerTreeViewDataProvider(viewId, { showCollapseAll: !!options.showCollapseAll, canSelectMany: !!options.canSelectMany, dropMimeTypes, dragMimeTypes, hasHandleDrag, hasHandleDrop, supportsFileDataTransfers });
9697
const treeView = this.createExtHostTreeView(viewId, options, extension);
9798
return {
9899
get onDidCollapseElement() { return treeView.onDidCollapseElement; },

src/vs/workbench/api/test/browser/mainThreadTreeViews.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ suite('MainThreadHostTreeView', function () {
7575
}
7676
drain(): any { return null; }
7777
}, new TestViewsService(), new TestNotificationService(), testExtensionService, new NullLogService());
78-
mainThreadTreeViews.$registerTreeViewDataProvider(testTreeViewId, { showCollapseAll: false, canSelectMany: false, dropMimeTypes: [], dragMimeTypes: [], hasHandleDrag: false, hasHandleDrop: false });
78+
mainThreadTreeViews.$registerTreeViewDataProvider(testTreeViewId, { showCollapseAll: false, canSelectMany: false, dropMimeTypes: [], dragMimeTypes: [], hasHandleDrag: false, hasHandleDrop: false, supportsFileDataTransfers: false });
7979
await testExtensionService.whenInstalledExtensionsRegistered();
8080
});
8181

src/vs/workbench/browser/parts/views/treeView.ts

Lines changed: 26 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ import { IExtensionService } from 'vs/workbench/services/extensions/common/exten
6666
import { IHoverService } from 'vs/workbench/services/hover/browser/hover';
6767
import { ThemeSettings } from 'vs/workbench/services/themes/common/workbenchThemeService';
6868
import { ITreeViewsService } from 'vs/workbench/services/views/browser/treeViewsService';
69-
import { CodeDataTransfers } from 'vs/platform/dnd/browser/dnd';
69+
import { CodeDataTransfers, FileAdditionalNativeProperties } from 'vs/platform/dnd/browser/dnd';
7070

7171
export class TreeViewPane extends ViewPane {
7272

@@ -1503,40 +1503,21 @@ export class CustomTreeViewDragAndDrop implements ITreeDragAndDrop<ITreeItem> {
15031503
}
15041504
const treeDataTransfer = new VSDataTransfer();
15051505
const uris: URI[] = [];
1506-
let itemsCount = Array.from(originalEvent.dataTransfer.items).reduce((previous, current) => {
1507-
if ((current.kind === 'string') || (current.kind === 'file')) {
1508-
return previous + 1;
1509-
}
1510-
return previous;
1511-
}, 0);
15121506

15131507
let treeSourceInfo: TreeDragSourceInfo | undefined;
15141508
let willDropUuid: string | undefined;
15151509
if (this.treeItemsTransfer.hasData(DraggedTreeItemsIdentifier.prototype)) {
15161510
willDropUuid = this.treeItemsTransfer.getData(DraggedTreeItemsIdentifier.prototype)![0].identifier;
15171511
}
1518-
await new Promise<void>(resolve => {
1519-
function decrementStringCount() {
1520-
itemsCount--;
1521-
if (itemsCount === 0) {
1522-
// Check if there are uris to add and add them
1523-
if (uris.length) {
1524-
treeDataTransfer.setString(Mimes.uriList, uris.map(uri => uri.toString()).join('\n'));
1525-
}
1526-
resolve();
1527-
}
1528-
}
15291512

1530-
if (!originalEvent.dataTransfer) {
1531-
return;
1532-
}
1533-
for (const dataItem of originalEvent.dataTransfer.items) {
1534-
const type = dataItem.type;
1535-
const kind = dataItem.kind;
1536-
const convertedType = this.convertKnownMimes(type, kind).type;
1537-
if ((INTERNAL_MIME_TYPES.indexOf(convertedType) < 0)
1538-
&& (convertedType === this.treeMimeType) || (dndController.dropMimeTypes.indexOf(convertedType) >= 0)) {
1539-
if (dataItem.kind === 'string') {
1513+
await Promise.all([...originalEvent.dataTransfer.items].map(async dataItem => {
1514+
const type = dataItem.type;
1515+
const kind = dataItem.kind;
1516+
const convertedType = this.convertKnownMimes(type, kind).type;
1517+
if ((INTERNAL_MIME_TYPES.indexOf(convertedType) < 0)
1518+
&& (convertedType === this.treeMimeType) || (dndController.dropMimeTypes.indexOf(convertedType) >= 0)) {
1519+
if (dataItem.kind === 'string') {
1520+
await new Promise<void>(resolve =>
15401521
dataItem.getAsString(dataValue => {
15411522
if (convertedType === this.treeMimeType) {
15421523
treeSourceInfo = JSON.parse(dataValue);
@@ -1545,20 +1526,27 @@ export class CustomTreeViewDragAndDrop implements ITreeDragAndDrop<ITreeItem> {
15451526
const converted = this.convertKnownMimes(type, kind, dataValue);
15461527
treeDataTransfer.setString(converted.type, converted.value + '');
15471528
}
1548-
decrementStringCount();
1549-
});
1550-
} else if (dataItem.kind === 'file') {
1551-
const dataValue = dataItem.getAsFile();
1552-
if (dataValue) {
1553-
uris.push(URI.file(dataValue.path));
1529+
resolve();
1530+
}));
1531+
} else if (dataItem.kind === 'file') {
1532+
const file = dataItem.getAsFile();
1533+
if (file) {
1534+
uris.push(URI.file(file.path));
1535+
const uri = (file as FileAdditionalNativeProperties).path ? URI.parse((file as FileAdditionalNativeProperties).path!) : undefined;
1536+
if (dndController.supportsFileDataTransfers) {
1537+
treeDataTransfer.setFile(type, file.name, uri, async () => {
1538+
return new Uint8Array(await file.arrayBuffer());
1539+
});
15541540
}
1555-
decrementStringCount();
15561541
}
1557-
} else if (dataItem.kind === 'string' || dataItem.kind === 'file') {
1558-
decrementStringCount();
15591542
}
15601543
}
1561-
});
1544+
}));
1545+
1546+
// Check if there are uris to add and add them
1547+
if (uris.length) {
1548+
treeDataTransfer.setString(Mimes.uriList, uris.map(uri => uri.toString()).join('\n'));
1549+
}
15621550

15631551
const additionalWillDropPromise = this.treeViewsDragAndDropService.removeDragOperationTransfer(willDropUuid);
15641552
if (!additionalWillDropPromise) {

src/vs/workbench/common/views.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -831,6 +831,7 @@ export interface ITreeViewDataProvider {
831831
export interface ITreeViewDragAndDropController {
832832
readonly dropMimeTypes: string[];
833833
readonly dragMimeTypes: string[];
834+
readonly supportsFileDataTransfers: boolean;
834835
handleDrag(sourceTreeItemHandles: string[], operationUuid: string, token: CancellationToken): Promise<VSDataTransfer | undefined>;
835836
handleDrop(elements: VSDataTransfer, target: ITreeItem | undefined, token: CancellationToken, operationUuid?: string, sourceTreeId?: string, sourceTreeItemHandles?: string[]): Promise<void>;
836837
}

0 commit comments

Comments
 (0)