mirror of
https://github.com/Microsoft/vscode
synced 2024-09-13 21:55:38 +00:00
Tree dnd feedback
This commit is contained in:
parent
8a3b1f4c4c
commit
a64e8e5673
|
@ -11,6 +11,7 @@ export namespace Mimes {
|
||||||
export const unknown = 'application/unknown';
|
export const unknown = 'application/unknown';
|
||||||
export const markdown = 'text/markdown';
|
export const markdown = 'text/markdown';
|
||||||
export const latex = 'text/latex';
|
export const latex = 'text/latex';
|
||||||
|
export const uriList = 'text/uri-list';
|
||||||
}
|
}
|
||||||
|
|
||||||
interface MapExtToMediaMimes {
|
interface MapExtToMediaMimes {
|
||||||
|
|
|
@ -33,14 +33,14 @@ export class MainThreadTreeViews extends Disposable implements MainThreadTreeVie
|
||||||
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostTreeViews);
|
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostTreeViews);
|
||||||
}
|
}
|
||||||
|
|
||||||
async $registerTreeViewDataProvider(treeViewId: string, options: { showCollapseAll: boolean; canSelectMany: boolean; dropMimeTypes: string[] | undefined; dragMimeTypes: string[] | undefined; hasHandleDrag: boolean }): Promise<void> {
|
async $registerTreeViewDataProvider(treeViewId: string, options: { showCollapseAll: boolean; canSelectMany: boolean; dropMimeTypes: string[]; dragMimeTypes: string[]; hasHandleDrag: boolean }): Promise<void> {
|
||||||
this.logService.trace('MainThreadTreeViews#$registerTreeViewDataProvider', treeViewId, options);
|
this.logService.trace('MainThreadTreeViews#$registerTreeViewDataProvider', treeViewId, options);
|
||||||
|
|
||||||
this.extensionService.whenInstalledExtensionsRegistered().then(() => {
|
this.extensionService.whenInstalledExtensionsRegistered().then(() => {
|
||||||
const dataProvider = new TreeViewDataProvider(treeViewId, this._proxy, this.notificationService);
|
const dataProvider = new TreeViewDataProvider(treeViewId, this._proxy, this.notificationService);
|
||||||
this._dataProviders.set(treeViewId, dataProvider);
|
this._dataProviders.set(treeViewId, dataProvider);
|
||||||
const dndController = options.dropMimeTypes
|
const dndController = options.dropMimeTypes
|
||||||
? new TreeViewDragAndDropController(treeViewId, options.dropMimeTypes, options.dragMimeTypes ?? [], options.hasHandleDrag, this._proxy) : undefined;
|
? new TreeViewDragAndDropController(treeViewId, options.dropMimeTypes, options.dragMimeTypes, options.hasHandleDrag, this._proxy) : undefined;
|
||||||
const viewer = this.getTreeView(treeViewId);
|
const viewer = this.getTreeView(treeViewId);
|
||||||
if (viewer) {
|
if (viewer) {
|
||||||
// Order is important here. The internal tree isn't created until the dataProvider is set.
|
// Order is important here. The internal tree isn't created until the dataProvider is set.
|
||||||
|
|
|
@ -257,7 +257,7 @@ export interface MainThreadTextEditorsShape extends IDisposable {
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface MainThreadTreeViewsShape extends IDisposable {
|
export interface MainThreadTreeViewsShape extends IDisposable {
|
||||||
$registerTreeViewDataProvider(treeViewId: string, options: { showCollapseAll: boolean; canSelectMany: boolean; dropMimeTypes: string[] | undefined; dragMimeTypes: string[] | undefined; hasHandleDrag: boolean }): Promise<void>;
|
$registerTreeViewDataProvider(treeViewId: string, options: { showCollapseAll: boolean; canSelectMany: boolean; dropMimeTypes: string[]; dragMimeTypes: string[]; hasHandleDrag: boolean }): Promise<void>;
|
||||||
$refresh(treeViewId: string, itemsToRefresh?: { [treeItemHandle: string]: ITreeItem }): Promise<void>;
|
$refresh(treeViewId: string, itemsToRefresh?: { [treeItemHandle: string]: ITreeItem }): Promise<void>;
|
||||||
$reveal(treeViewId: string, itemInfo: { item: ITreeItem; parentChain: ITreeItem[] } | undefined, options: IRevealOptions): Promise<void>;
|
$reveal(treeViewId: string, itemInfo: { item: ITreeItem; parentChain: ITreeItem[] } | undefined, options: IRevealOptions): Promise<void>;
|
||||||
$setMessage(treeViewId: string, message: string): void;
|
$setMessage(treeViewId: string, message: string): void;
|
||||||
|
|
|
@ -87,8 +87,8 @@ export class ExtHostTreeViews implements ExtHostTreeViewsShape {
|
||||||
if (!options || !options.treeDataProvider) {
|
if (!options || !options.treeDataProvider) {
|
||||||
throw new Error('Options with treeDataProvider is mandatory');
|
throw new Error('Options with treeDataProvider is mandatory');
|
||||||
}
|
}
|
||||||
const dropMimeTypes = options.dragAndDropController?.dropMimeTypes;
|
const dropMimeTypes = options.dragAndDropController?.dropMimeTypes ?? [];
|
||||||
const dragMimeTypes = options.dragAndDropController?.dragMimeTypes;
|
const dragMimeTypes = options.dragAndDropController?.dragMimeTypes ?? [];
|
||||||
const hasHandleDrag = !!options.dragAndDropController?.handleDrag;
|
const hasHandleDrag = !!options.dragAndDropController?.handleDrag;
|
||||||
const registerPromise = this._proxy.$registerTreeViewDataProvider(viewId, { showCollapseAll: !!options.showCollapseAll, canSelectMany: !!options.canSelectMany, dropMimeTypes, dragMimeTypes, hasHandleDrag: hasHandleDrag });
|
const registerPromise = this._proxy.$registerTreeViewDataProvider(viewId, { showCollapseAll: !!options.showCollapseAll, canSelectMany: !!options.canSelectMany, dropMimeTypes, dragMimeTypes, hasHandleDrag: hasHandleDrag });
|
||||||
const treeView = this.createExtHostTreeView(viewId, options, extension);
|
const treeView = this.createExtHostTreeView(viewId, options, extension);
|
||||||
|
@ -457,7 +457,7 @@ class ExtHostTreeView<T> extends Disposable {
|
||||||
if (!target) {
|
if (!target) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
return asPromise(() => this.dndController?.handleDrop(treeDataTransfer, target, token));
|
return asPromise(() => this.dndController?.handleDrop(target, treeDataTransfer, token));
|
||||||
}
|
}
|
||||||
|
|
||||||
get hasResolve(): boolean {
|
get hasResolve(): boolean {
|
||||||
|
|
|
@ -2351,7 +2351,7 @@ export enum TreeItemCollapsibleState {
|
||||||
@es5ClassCompat
|
@es5ClassCompat
|
||||||
export class TreeDataTransferItem {
|
export class TreeDataTransferItem {
|
||||||
async asString(): Promise<string> {
|
async asString(): Promise<string> {
|
||||||
return JSON.stringify(this.value);
|
return typeof this.value === 'string' ? this.value : JSON.stringify(this.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(public readonly value: any) { }
|
constructor(public readonly value: any) { }
|
||||||
|
|
|
@ -157,12 +157,13 @@ function createDraggedEditorInputFromRawResourcesData(rawResourcesData: string |
|
||||||
|
|
||||||
export async function extractTreeDropData(dataTransfer: ITreeDataTransfer): Promise<Array<IDraggedResourceEditorInput>> {
|
export async function extractTreeDropData(dataTransfer: ITreeDataTransfer): Promise<Array<IDraggedResourceEditorInput>> {
|
||||||
const editors: IDraggedResourceEditorInput[] = [];
|
const editors: IDraggedResourceEditorInput[] = [];
|
||||||
const resourcesKey = DataTransfers.RESOURCES.toLowerCase();
|
const resourcesKey = Mimes.uriList.toLowerCase();
|
||||||
|
|
||||||
// Data Transfer: Resources
|
// Data Transfer: Resources
|
||||||
if (dataTransfer.has(resourcesKey)) {
|
if (dataTransfer.has(resourcesKey)) {
|
||||||
try {
|
try {
|
||||||
const rawResourcesData = await dataTransfer.get(resourcesKey)?.asString();
|
const asString = await dataTransfer.get(resourcesKey)?.asString();
|
||||||
|
const rawResourcesData = JSON.stringify(asString?.split('\\n').filter(value => !value.startsWith('#')));
|
||||||
editors.push(...createDraggedEditorInputFromRawResourcesData(rawResourcesData));
|
editors.push(...createDraggedEditorInputFromRawResourcesData(rawResourcesData));
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// Invalid transfer
|
// Invalid transfer
|
||||||
|
|
|
@ -39,7 +39,7 @@ import { isString } from 'vs/base/common/types';
|
||||||
import { ILabelService } from 'vs/platform/label/common/label';
|
import { ILabelService } from 'vs/platform/label/common/label';
|
||||||
import { IListVirtualDelegate, IIdentityProvider } from 'vs/base/browser/ui/list/list';
|
import { IListVirtualDelegate, IIdentityProvider } from 'vs/base/browser/ui/list/list';
|
||||||
import { ITreeRenderer, ITreeNode, IAsyncDataSource, ITreeContextMenuEvent, ITreeDragAndDrop, ITreeDragOverReaction, TreeDragOverBubble } from 'vs/base/browser/ui/tree/tree';
|
import { ITreeRenderer, ITreeNode, IAsyncDataSource, ITreeContextMenuEvent, ITreeDragAndDrop, ITreeDragOverReaction, TreeDragOverBubble } from 'vs/base/browser/ui/tree/tree';
|
||||||
import { IDragAndDropData } from 'vs/base/browser/dnd';
|
import { DataTransfers, IDragAndDropData } from 'vs/base/browser/dnd';
|
||||||
import { FuzzyScore, createMatches } from 'vs/base/common/filters';
|
import { FuzzyScore, createMatches } from 'vs/base/common/filters';
|
||||||
import { CollapseAllAction } from 'vs/base/browser/ui/tree/treeDefaults';
|
import { CollapseAllAction } from 'vs/base/browser/ui/tree/treeDefaults';
|
||||||
import { isFalsyOrWhitespace } from 'vs/base/common/strings';
|
import { isFalsyOrWhitespace } from 'vs/base/common/strings';
|
||||||
|
@ -62,6 +62,7 @@ import { Schemas } from 'vs/base/common/network';
|
||||||
import { ITreeViewsDragAndDropService } from 'vs/workbench/services/views/common/treeViewsDragAndDropService';
|
import { ITreeViewsDragAndDropService } from 'vs/workbench/services/views/common/treeViewsDragAndDropService';
|
||||||
import { generateUuid } from 'vs/base/common/uuid';
|
import { generateUuid } from 'vs/base/common/uuid';
|
||||||
import { ILogService } from 'vs/platform/log/common/log';
|
import { ILogService } from 'vs/platform/log/common/log';
|
||||||
|
import { Mimes } from 'vs/base/common/mime';
|
||||||
|
|
||||||
export class TreeViewPane extends ViewPane {
|
export class TreeViewPane extends ViewPane {
|
||||||
|
|
||||||
|
@ -1266,7 +1267,7 @@ export class CustomTreeViewDragAndDrop implements ITreeDragAndDrop<ITreeItem> {
|
||||||
@IInstantiationService private readonly instantiationService: IInstantiationService,
|
@IInstantiationService private readonly instantiationService: IInstantiationService,
|
||||||
@ITreeViewsDragAndDropService private readonly treeViewsDragAndDropService: ITreeViewsDragAndDropService<ITreeDataTransfer>,
|
@ITreeViewsDragAndDropService private readonly treeViewsDragAndDropService: ITreeViewsDragAndDropService<ITreeDataTransfer>,
|
||||||
@ILogService private readonly logService: ILogService) {
|
@ILogService private readonly logService: ILogService) {
|
||||||
this.treeMimeType = `tree/${treeId.toLowerCase()}`;
|
this.treeMimeType = `application/vnd.code.tree.${treeId.toLowerCase()}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
private dndController: ITreeViewDragAndDropController | undefined;
|
private dndController: ITreeViewDragAndDropController | undefined;
|
||||||
|
@ -1283,7 +1284,11 @@ export class CustomTreeViewDragAndDrop implements ITreeDragAndDrop<ITreeItem> {
|
||||||
this.dragCancellationToken = new CancellationTokenSource();
|
this.dragCancellationToken = new CancellationTokenSource();
|
||||||
this.treeViewsDragAndDropService.addDragOperationTransfer(uuid, this.dndController.handleDrag(itemHandles, uuid, this.dragCancellationToken.token));
|
this.treeViewsDragAndDropService.addDragOperationTransfer(uuid, this.dndController.handleDrag(itemHandles, uuid, this.dragCancellationToken.token));
|
||||||
originalEvent.dataTransfer.setData(TREE_DRAG_UUID_MIME, uuid);
|
originalEvent.dataTransfer.setData(TREE_DRAG_UUID_MIME, uuid);
|
||||||
this.treeItemsTransfer.setData([new DraggedTreeItemsIdentifier(uuid)], DraggedTreeItemsIdentifier.prototype);
|
if (this.dndController.dragMimeTypes.find((element) => element === Mimes.uriList)) {
|
||||||
|
this.treeItemsTransfer.setData([new DraggedTreeItemsIdentifier(uuid)], DraggedTreeItemsIdentifier.prototype);
|
||||||
|
// Add the type that the editor knows
|
||||||
|
originalEvent.dataTransfer?.setData(DataTransfers.RESOURCES, '');
|
||||||
|
}
|
||||||
this.dndController.dragMimeTypes.forEach(supportedType => {
|
this.dndController.dragMimeTypes.forEach(supportedType => {
|
||||||
originalEvent.dataTransfer?.setData(supportedType, '');
|
originalEvent.dataTransfer?.setData(supportedType, '');
|
||||||
});
|
});
|
||||||
|
|
|
@ -68,7 +68,6 @@ declare module 'vscode' {
|
||||||
/**
|
/**
|
||||||
* Provides support for drag and drop in `TreeView`.
|
* Provides support for drag and drop in `TreeView`.
|
||||||
*/
|
*/
|
||||||
// todo@API formalize mime types, either `text/uri-list` and or `application/vnd.code.XYZ` (see NotebookOutputItem)
|
|
||||||
export interface TreeDragAndDropController<T> {
|
export interface TreeDragAndDropController<T> {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -76,7 +75,7 @@ declare module 'vscode' {
|
||||||
* This could be well-defined, existing, mime types, and also mime types defined by the extension.
|
* This could be well-defined, existing, mime types, and also mime types defined by the extension.
|
||||||
*
|
*
|
||||||
* Each tree will automatically support drops from it's own `DragAndDropController`. To support drops from other trees,
|
* Each tree will automatically support drops from it's own `DragAndDropController`. To support drops from other trees,
|
||||||
* you will need to add the mime type of that tree. The mime type of a tree is of the format `tree/treeidlowercase`.
|
* you will need to add the mime type of that tree. The mime type of a tree is of the format `application/vnd.code.tree.treeidlowercase`.
|
||||||
*
|
*
|
||||||
* To learn the mime type of a dragged item:
|
* To learn the mime type of a dragged item:
|
||||||
* 1. Set up your `DragAndDropController`
|
* 1. Set up your `DragAndDropController`
|
||||||
|
@ -98,8 +97,8 @@ declare module 'vscode' {
|
||||||
* When the items are dropped on **another tree item** in **the same tree**, your `TreeDataTransferItem` objects
|
* When the items are dropped on **another tree item** in **the same tree**, your `TreeDataTransferItem` objects
|
||||||
* will be preserved. See the documentation for `TreeDataTransferItem` for how best to take advantage of this.
|
* will be preserved. See the documentation for `TreeDataTransferItem` for how best to take advantage of this.
|
||||||
*
|
*
|
||||||
* To add a data transfer item that can be dragged into the editor, use the application specific mime type "resourceurls".
|
* To add a data transfer item that can be dragged into the editor, use the application specific mime type "text/uri-list".
|
||||||
* The data for "resourceurls" should be an array of `toString()`ed Uris. To specify a cursor position in the file,
|
* The data for "text/uri-list" should be a string with `toString()`ed Uris separated by newlines. To specify a cursor position in the file,
|
||||||
* set the Uri's fragment to `L3,5`, where 3 is the line number and 5 is the column number.
|
* set the Uri's fragment to `L3,5`, where 3 is the line number and 5 is the column number.
|
||||||
*
|
*
|
||||||
* @param source The source items for the drag and drop operation.
|
* @param source The source items for the drag and drop operation.
|
||||||
|
@ -115,9 +114,8 @@ declare module 'vscode' {
|
||||||
*
|
*
|
||||||
* @param source The data transfer items of the source of the drag.
|
* @param source The data transfer items of the source of the drag.
|
||||||
* @param target The target tree element that the drop is occurring on.
|
* @param target The target tree element that the drop is occurring on.
|
||||||
* @param token TODO @alexr00: When would this operation actually be cancelled?
|
* @param token A cancellation token indicating that the drop has been cancelled.
|
||||||
*/
|
*/
|
||||||
// TODO@API align order of TreeDataTransfer and T with handleDrag
|
handleDrop(target: T, source: TreeDataTransfer, token: CancellationToken): Thenable<void> | void;
|
||||||
handleDrop(source: TreeDataTransfer, target: T, token: CancellationToken): Thenable<void> | void;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue