mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-16 10:58:30 -05:00
Integrate drag and drop api (#16500)
* Initial implementation of drag and drop api (#122239) * Add drag and drop controller (#123542) * Tree data transfer dnd (#128666) * add drop method to sql files Co-authored-by: Alex Ross <alros@microsoft.com>
This commit is contained in:
@@ -10,6 +10,7 @@ export interface ExtensionGlobalMemento extends vscode.Memento {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class MockExtensionContext implements vscode.ExtensionContext {
|
export class MockExtensionContext implements vscode.ExtensionContext {
|
||||||
|
extensionRuntime = 1;
|
||||||
logger: undefined;
|
logger: undefined;
|
||||||
logPath: './';
|
logPath: './';
|
||||||
subscriptions: { dispose(): any; }[];
|
subscriptions: { dispose(): any; }[];
|
||||||
|
|||||||
1
extensions/notebook/src/typings/refs.d.ts
vendored
1
extensions/notebook/src/typings/refs.d.ts
vendored
@@ -6,5 +6,6 @@
|
|||||||
/// <reference path='../../../../src/sql/azdata.d.ts'/>
|
/// <reference path='../../../../src/sql/azdata.d.ts'/>
|
||||||
/// <reference path='../../../../src/sql/azdata.proposed.d.ts'/>
|
/// <reference path='../../../../src/sql/azdata.proposed.d.ts'/>
|
||||||
/// <reference path='../../../../src/vs/vscode.d.ts'/>
|
/// <reference path='../../../../src/vs/vscode.d.ts'/>
|
||||||
|
/// <reference path='../../../../src/vs/vscode.proposed.d.ts' />
|
||||||
/// <reference path='../../../big-data-cluster/src/bdc.d.ts'/>
|
/// <reference path='../../../big-data-cluster/src/bdc.d.ts'/>
|
||||||
/// <reference types='@types/node'/>
|
/// <reference types='@types/node'/>
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import { Emitter } from 'vs/base/common/event';
|
|||||||
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
||||||
import { assign } from 'vs/base/common/objects';
|
import { assign } from 'vs/base/common/objects';
|
||||||
import { ILogService } from 'vs/platform/log/common/log';
|
import { ILogService } from 'vs/platform/log/common/log';
|
||||||
|
import { TreeDataTransferDTO } from 'vs/workbench/api/common/shared/treeDataTransfer';
|
||||||
|
|
||||||
export class ExtHostModelViewTreeViews implements ExtHostModelViewTreeViewsShape {
|
export class ExtHostModelViewTreeViews implements ExtHostModelViewTreeViewsShape {
|
||||||
private _proxy: MainThreadModelViewShape;
|
private _proxy: MainThreadModelViewShape;
|
||||||
@@ -85,6 +86,10 @@ export class ExtHostModelViewTreeViews implements ExtHostModelViewTreeViewsShape
|
|||||||
return Promise.resolve(undefined);
|
return Promise.resolve(undefined);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$onDrop(treeViewId: string, treeDataTransferDTO: TreeDataTransferDTO, newParentItemHandle: string): Promise<void> {
|
||||||
|
return Promise.resolve(undefined);
|
||||||
|
}
|
||||||
|
|
||||||
private createExtHostTreeViewer<T>(handle: number, id: string, dataProvider: azdata.TreeComponentDataProvider<T>, extension: IExtensionDescription, logService: ILogService): ExtHostTreeView<T> {
|
private createExtHostTreeViewer<T>(handle: number, id: string, dataProvider: azdata.TreeComponentDataProvider<T>, extension: IExtensionDescription, logService: ILogService): ExtHostTreeView<T> {
|
||||||
const treeView = new ExtHostTreeView<T>(handle, id, dataProvider, this._proxy, undefined, extension, logService);
|
const treeView = new ExtHostTreeView<T>(handle, id, dataProvider, this._proxy, undefined, extension, logService);
|
||||||
this.treeViews.set(`${handle}-${id}`, treeView);
|
this.treeViews.set(`${handle}-${id}`, treeView);
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ import { IUndoStopOptions } from 'vs/workbench/api/common/extHost.protocol';
|
|||||||
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
||||||
import { IQueryEvent } from 'sql/workbench/services/query/common/queryModel';
|
import { IQueryEvent } from 'sql/workbench/services/query/common/queryModel';
|
||||||
import { EditorViewColumn } from 'vs/workbench/api/common/shared/editor';
|
import { EditorViewColumn } from 'vs/workbench/api/common/shared/editor';
|
||||||
|
import { TreeDataTransferDTO } from 'vs/workbench/api/common/shared/treeDataTransfer';
|
||||||
|
|
||||||
export abstract class ExtHostAccountManagementShape {
|
export abstract class ExtHostAccountManagementShape {
|
||||||
$autoOAuthCancelled(handle: number): Thenable<void> { throw ni(); }
|
$autoOAuthCancelled(handle: number): Thenable<void> { throw ni(); }
|
||||||
@@ -740,6 +741,7 @@ export interface ExtHostModelViewShape {
|
|||||||
|
|
||||||
export interface ExtHostModelViewTreeViewsShape {
|
export interface ExtHostModelViewTreeViewsShape {
|
||||||
$getChildren(treeViewId: string, treeItemHandle?: string): Promise<ITreeComponentItem[]>;
|
$getChildren(treeViewId: string, treeItemHandle?: string): Promise<ITreeComponentItem[]>;
|
||||||
|
$onDrop(treeViewId: string, treeDataTransfer: TreeDataTransferDTO, newParentTreeItemHandle: string): Promise<void>;
|
||||||
$createTreeView(handle: number, componentId: string, options: { treeDataProvider: vscode.TreeDataProvider<any> }, extension: IExtensionDescription): azdata.TreeComponentView<any>;
|
$createTreeView(handle: number, componentId: string, options: { treeDataProvider: vscode.TreeDataProvider<any> }, extension: IExtensionDescription): azdata.TreeComponentView<any>;
|
||||||
$onNodeCheckedChanged(treeViewId: string, treeItemHandle?: string, checked?: boolean): void;
|
$onNodeCheckedChanged(treeViewId: string, treeItemHandle?: string, checked?: boolean): void;
|
||||||
$onNodeSelected(treeViewId: string, nodes: string[]): void;
|
$onNodeSelected(treeViewId: string, nodes: string[]): void;
|
||||||
|
|||||||
34
src/vs/vscode.proposed.d.ts
vendored
34
src/vs/vscode.proposed.d.ts
vendored
@@ -881,6 +881,40 @@ declare module 'vscode' {
|
|||||||
}
|
}
|
||||||
//#endregion
|
//#endregion
|
||||||
|
|
||||||
|
//#region Custom Tree View Drag and Drop https://github.com/microsoft/vscode/issues/32592
|
||||||
|
export interface TreeViewOptions<T> {
|
||||||
|
dragAndDropController?: DragAndDropController<T>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface TreeDataTransferItem {
|
||||||
|
asString(): Thenable<string>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface TreeDataTransfer {
|
||||||
|
/**
|
||||||
|
* A map containing a mapping of the mime type of the corresponding data.
|
||||||
|
* The type for tree elements is text/treeitem.
|
||||||
|
* For example, you can reconstruct the your tree elements:
|
||||||
|
* ```ts
|
||||||
|
* JSON.parse(await (items.get('text/treeitems')!.asString()))
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
items: Map<string, TreeDataTransferItem>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface DragAndDropController<T> extends Disposable {
|
||||||
|
readonly supportedTypes: string[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extensions should fire `TreeDataProvider.onDidChangeTreeData` for any elements that need to be refreshed.
|
||||||
|
*
|
||||||
|
* @param source
|
||||||
|
* @param target
|
||||||
|
*/
|
||||||
|
onDrop(source: TreeDataTransfer, target: T): Thenable<void>;
|
||||||
|
}
|
||||||
|
//#endregion
|
||||||
|
|
||||||
//#region Task presentation group: https://github.com/microsoft/vscode/issues/47265
|
//#region Task presentation group: https://github.com/microsoft/vscode/issues/47265
|
||||||
export interface TaskPresentationOptions {
|
export interface TaskPresentationOptions {
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
import { Disposable } from 'vs/base/common/lifecycle';
|
import { Disposable } from 'vs/base/common/lifecycle';
|
||||||
import { ExtHostContext, MainThreadTreeViewsShape, ExtHostTreeViewsShape, MainContext, IExtHostContext } from 'vs/workbench/api/common/extHost.protocol';
|
import { ExtHostContext, MainThreadTreeViewsShape, ExtHostTreeViewsShape, MainContext, IExtHostContext } from 'vs/workbench/api/common/extHost.protocol';
|
||||||
import { ITreeViewDataProvider, ITreeItem, IViewsService, ITreeView, IViewsRegistry, ITreeViewDescriptor, IRevealOptions, Extensions, ResolvableTreeItem } from 'vs/workbench/common/views';
|
import { ITreeViewDataProvider, ITreeItem, IViewsService, ITreeView, IViewsRegistry, ITreeViewDescriptor, IRevealOptions, Extensions, ResolvableTreeItem, ITreeViewDragAndDropController, ITreeDataTransfer } from 'vs/workbench/common/views';
|
||||||
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
|
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
|
||||||
import { distinct } from 'vs/base/common/arrays';
|
import { distinct } from 'vs/base/common/arrays';
|
||||||
import { INotificationService } from 'vs/platform/notification/common/notification';
|
import { INotificationService } from 'vs/platform/notification/common/notification';
|
||||||
@@ -14,6 +14,7 @@ import { Registry } from 'vs/platform/registry/common/platform';
|
|||||||
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
|
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
|
||||||
import { ILogService } from 'vs/platform/log/common/log';
|
import { ILogService } from 'vs/platform/log/common/log';
|
||||||
import { IConnectionTreeService } from 'sql/workbench/services/connection/common/connectionTreeService';
|
import { IConnectionTreeService } from 'sql/workbench/services/connection/common/connectionTreeService';
|
||||||
|
import { TreeDataTransferConverter } from 'vs/workbench/api/common/shared/treeDataTransfer';
|
||||||
|
|
||||||
@extHostNamedCustomer(MainContext.MainThreadTreeViews)
|
@extHostNamedCustomer(MainContext.MainThreadTreeViews)
|
||||||
export class MainThreadTreeViews extends Disposable implements MainThreadTreeViewsShape {
|
export class MainThreadTreeViews extends Disposable implements MainThreadTreeViewsShape {
|
||||||
@@ -33,18 +34,20 @@ 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 }): Promise<void> {
|
async $registerTreeViewDataProvider(treeViewId: string, options: { showCollapseAll: boolean, canSelectMany: boolean, canDragAndDrop: 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.canDragAndDrop ? new TreeViewDragAndDropController(treeViewId, 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.
|
||||||
// Set all other properties first!
|
// Set all other properties first!
|
||||||
viewer.showCollapseAllAction = !!options.showCollapseAll;
|
viewer.showCollapseAllAction = !!options.showCollapseAll;
|
||||||
viewer.canSelectMany = !!options.canSelectMany;
|
viewer.canSelectMany = !!options.canSelectMany;
|
||||||
|
viewer.dragAndDropController = dndController;
|
||||||
viewer.dataProvider = dataProvider;
|
viewer.dataProvider = dataProvider;
|
||||||
this.registerListeners(treeViewId, viewer);
|
this.registerListeners(treeViewId, viewer);
|
||||||
this._proxy.$setVisible(treeViewId, viewer.visible);
|
this._proxy.$setVisible(treeViewId, viewer.visible);
|
||||||
@@ -171,6 +174,16 @@ export class MainThreadTreeViews extends Disposable implements MainThreadTreeVie
|
|||||||
// {{SQL CARBON EDIT}}
|
// {{SQL CARBON EDIT}}
|
||||||
export type TreeItemHandle = string;
|
export type TreeItemHandle = string;
|
||||||
|
|
||||||
|
class TreeViewDragAndDropController implements ITreeViewDragAndDropController {
|
||||||
|
|
||||||
|
constructor(private readonly treeViewId: string,
|
||||||
|
private readonly _proxy: ExtHostTreeViewsShape) { }
|
||||||
|
|
||||||
|
async onDrop(dataTransfer: ITreeDataTransfer, targetTreeItem: ITreeItem): Promise<void> {
|
||||||
|
return this._proxy.$onDrop(this.treeViewId, await TreeDataTransferConverter.toTreeDataTransferDTO(dataTransfer), targetTreeItem.handle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// {{SQL CARBON EDIT}}
|
// {{SQL CARBON EDIT}}
|
||||||
export class TreeViewDataProvider implements ITreeViewDataProvider {
|
export class TreeViewDataProvider implements ITreeViewDataProvider {
|
||||||
|
|
||||||
@@ -195,7 +208,7 @@ export class TreeViewDataProvider implements ITreeViewDataProvider {
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
getItemsToRefresh(itemsToRefreshByHandle: { [treeItemHandle: string]: ITreeItem; }): ITreeItem[] {
|
getItemsToRefresh(itemsToRefreshByHandle: { [treeItemHandle: string]: ITreeItem }): ITreeItem[] {
|
||||||
const itemsToRefresh: ITreeItem[] = [];
|
const itemsToRefresh: ITreeItem[] = [];
|
||||||
if (itemsToRefreshByHandle) {
|
if (itemsToRefreshByHandle) {
|
||||||
for (const treeItemHandle of Object.keys(itemsToRefreshByHandle)) {
|
for (const treeItemHandle of Object.keys(itemsToRefreshByHandle)) {
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ import * as statusbar from 'vs/workbench/services/statusbar/common/statusbar';
|
|||||||
import { ClassifiedEvent, GDPRClassification, StrictPropertyCheck } from 'vs/platform/telemetry/common/gdprTypings';
|
import { ClassifiedEvent, GDPRClassification, StrictPropertyCheck } from 'vs/platform/telemetry/common/gdprTypings';
|
||||||
import { ITelemetryInfo } from 'vs/platform/telemetry/common/telemetry';
|
import { ITelemetryInfo } from 'vs/platform/telemetry/common/telemetry';
|
||||||
import { ThemeColor } from 'vs/platform/theme/common/themeService';
|
import { ThemeColor } from 'vs/platform/theme/common/themeService';
|
||||||
|
import { TreeDataTransferDTO } from 'vs/workbench/api/common/shared/treeDataTransfer';
|
||||||
import * as tasks from 'vs/workbench/api/common/shared/tasks';
|
import * as tasks from 'vs/workbench/api/common/shared/tasks';
|
||||||
import { IRevealOptions, ITreeItem } from 'vs/workbench/common/views';
|
import { IRevealOptions, ITreeItem } from 'vs/workbench/common/views';
|
||||||
import { IAdapterDescriptor, IConfig, IDebugSessionReplMode } from 'vs/workbench/contrib/debug/common/debug';
|
import { IAdapterDescriptor, IConfig, IDebugSessionReplMode } from 'vs/workbench/contrib/debug/common/debug';
|
||||||
@@ -293,7 +294,7 @@ export interface MainThreadTextEditorsShape extends IDisposable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface MainThreadTreeViewsShape extends IDisposable {
|
export interface MainThreadTreeViewsShape extends IDisposable {
|
||||||
$registerTreeViewDataProvider(treeViewId: string, options: { showCollapseAll: boolean, canSelectMany: boolean; }): Promise<void>;
|
$registerTreeViewDataProvider(treeViewId: string, options: { showCollapseAll: boolean, canSelectMany: boolean, canDragAndDrop: 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;
|
||||||
@@ -1234,6 +1235,7 @@ export interface ExtHostDocumentsAndEditorsShape {
|
|||||||
export interface ExtHostTreeViewsShape {
|
export interface ExtHostTreeViewsShape {
|
||||||
// {{SQL CARBON EDIT}}
|
// {{SQL CARBON EDIT}}
|
||||||
$getChildren(treeViewId: string, treeItemHandle?: string): Promise<sqlITreeItem[]>;
|
$getChildren(treeViewId: string, treeItemHandle?: string): Promise<sqlITreeItem[]>;
|
||||||
|
$onDrop(treeViewId: string, treeDataTransfer: TreeDataTransferDTO, newParentTreeItemHandle: string): Promise<void>;
|
||||||
$setExpanded(treeViewId: string, treeItemHandle: string, expanded: boolean): void;
|
$setExpanded(treeViewId: string, treeItemHandle: string, expanded: boolean): void;
|
||||||
$setSelection(treeViewId: string, treeItemHandles: string[]): void;
|
$setSelection(treeViewId: string, treeItemHandles: string[]): void;
|
||||||
$setVisible(treeViewId: string, visible: boolean): void;
|
$setVisible(treeViewId: string, visible: boolean): void;
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import { URI } from 'vs/base/common/uri';
|
|||||||
import { Emitter, Event } from 'vs/base/common/event';
|
import { Emitter, Event } from 'vs/base/common/event';
|
||||||
import { Disposable, DisposableStore, IDisposable } from 'vs/base/common/lifecycle';
|
import { Disposable, DisposableStore, IDisposable } from 'vs/base/common/lifecycle';
|
||||||
import { ExtHostTreeViewsShape, MainThreadTreeViewsShape } from './extHost.protocol';
|
import { ExtHostTreeViewsShape, MainThreadTreeViewsShape } from './extHost.protocol';
|
||||||
import { ITreeItem, TreeViewItemHandleArg, ITreeItemLabel, IRevealOptions } from 'vs/workbench/common/views';
|
import { ITreeItem, TreeViewItemHandleArg, ITreeItemLabel, IRevealOptions, TREE_ITEM_DATA_TRANSFER_TYPE } from 'vs/workbench/common/views';
|
||||||
import { ExtHostCommands, CommandsConverter } from 'vs/workbench/api/common/extHostCommands';
|
import { ExtHostCommands, CommandsConverter } from 'vs/workbench/api/common/extHostCommands';
|
||||||
import { asPromise } from 'vs/base/common/async';
|
import { asPromise } from 'vs/base/common/async';
|
||||||
import { TreeItemCollapsibleState, ThemeIcon, MarkdownString as MarkdownStringType } from 'vs/workbench/api/common/extHostTypes';
|
import { TreeItemCollapsibleState, ThemeIcon, MarkdownString as MarkdownStringType } from 'vs/workbench/api/common/extHostTypes';
|
||||||
@@ -22,6 +22,7 @@ import { MarkdownString } from 'vs/workbench/api/common/extHostTypeConverters';
|
|||||||
import { IMarkdownString } from 'vs/base/common/htmlContent';
|
import { IMarkdownString } from 'vs/base/common/htmlContent';
|
||||||
import { CancellationTokenSource } from 'vs/base/common/cancellation';
|
import { CancellationTokenSource } from 'vs/base/common/cancellation';
|
||||||
import { Command } from 'vs/editor/common/modes';
|
import { Command } from 'vs/editor/common/modes';
|
||||||
|
import { TreeDataTransferConverter, TreeDataTransferDTO } from 'vs/workbench/api/common/shared/treeDataTransfer';
|
||||||
|
|
||||||
// {{SQL CARBON EDIT}}
|
// {{SQL CARBON EDIT}}
|
||||||
import * as azdata from 'azdata';
|
import * as azdata from 'azdata';
|
||||||
@@ -86,7 +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 registerPromise = this._proxy.$registerTreeViewDataProvider(viewId, { showCollapseAll: !!options.showCollapseAll, canSelectMany: !!options.canSelectMany });
|
const canDragAndDrop = options.dragAndDropController !== undefined;
|
||||||
|
const registerPromise = this._proxy.$registerTreeViewDataProvider(viewId, { showCollapseAll: !!options.showCollapseAll, canSelectMany: !!options.canSelectMany, canDragAndDrop: canDragAndDrop });
|
||||||
const treeView = this.createExtHostTreeView(viewId, options, extension);
|
const treeView = this.createExtHostTreeView(viewId, options, extension);
|
||||||
return {
|
return {
|
||||||
get onDidCollapseElement() { return treeView.onDidCollapseElement; },
|
get onDidCollapseElement() { return treeView.onDidCollapseElement; },
|
||||||
@@ -129,6 +131,27 @@ export class ExtHostTreeViews implements ExtHostTreeViewsShape {
|
|||||||
return treeView.getChildren(treeItemHandle);
|
return treeView.getChildren(treeItemHandle);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async $onDrop(treeViewId: string, treeDataTransferDTO: TreeDataTransferDTO, newParentItemHandle: string): Promise<void> {
|
||||||
|
const treeView = this.treeViews.get(treeViewId);
|
||||||
|
if (!treeView) {
|
||||||
|
return Promise.reject(new Error(localize('treeView.notRegistered', 'No tree view with id \'{0}\' registered.', treeViewId)));
|
||||||
|
}
|
||||||
|
|
||||||
|
const treeDataTransfer = TreeDataTransferConverter.toITreeDataTransfer(treeDataTransferDTO);
|
||||||
|
if (treeDataTransfer.items.has(TREE_ITEM_DATA_TRANSFER_TYPE)) {
|
||||||
|
const sourceHandles: string[] = JSON.parse(await treeDataTransfer.items.get(TREE_ITEM_DATA_TRANSFER_TYPE)!.asString());
|
||||||
|
const sourceElements = sourceHandles.map(handle => treeView.getExtensionElement(handle)).filter(element => !!element);
|
||||||
|
if (sourceElements.length > 0) {
|
||||||
|
treeDataTransfer.items.set(TREE_ITEM_DATA_TRANSFER_TYPE, {
|
||||||
|
asString: async () => JSON.stringify(sourceElements)
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
treeDataTransfer.items.delete(TREE_ITEM_DATA_TRANSFER_TYPE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return treeView.onDrop(treeDataTransfer, newParentItemHandle);
|
||||||
|
}
|
||||||
|
|
||||||
async $hasResolve(treeViewId: string): Promise<boolean> {
|
async $hasResolve(treeViewId: string): Promise<boolean> {
|
||||||
const treeView = this.treeViews.get(treeViewId);
|
const treeView = this.treeViews.get(treeViewId);
|
||||||
if (!treeView) {
|
if (!treeView) {
|
||||||
@@ -199,6 +222,7 @@ export class ExtHostTreeView<T> extends Disposable {
|
|||||||
private static readonly ID_HANDLE_PREFIX = '1';
|
private static readonly ID_HANDLE_PREFIX = '1';
|
||||||
|
|
||||||
private readonly dataProvider: vscode.TreeDataProvider<T>;
|
private readonly dataProvider: vscode.TreeDataProvider<T>;
|
||||||
|
private readonly dndController: vscode.DragAndDropController<T> | undefined;
|
||||||
|
|
||||||
private roots: TreeNode[] | null = null;
|
private roots: TreeNode[] | null = null;
|
||||||
private elements: Map<TreeItemHandle, T> = new Map<TreeItemHandle, T>();
|
private elements: Map<TreeItemHandle, T> = new Map<TreeItemHandle, T>();
|
||||||
@@ -246,9 +270,11 @@ export class ExtHostTreeView<T> extends Disposable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.dataProvider = options.treeDataProvider;
|
this.dataProvider = options.treeDataProvider;
|
||||||
|
this.dndController = options.dragAndDropController;
|
||||||
|
|
||||||
// {{SQL CARBON EDIT}}
|
// {{SQL CARBON EDIT}}
|
||||||
if (this.proxy) {
|
if (this.proxy) {
|
||||||
this.proxy.$registerTreeViewDataProvider(viewId, { showCollapseAll: !!options.showCollapseAll, canSelectMany: !!options.canSelectMany });
|
this.proxy.$registerTreeViewDataProvider(viewId, { showCollapseAll: !!options.showCollapseAll, canSelectMany: !!options.canSelectMany, canDragAndDrop: options.dragAndDropController !== undefined });
|
||||||
}
|
}
|
||||||
if (this.dataProvider.onDidChangeTreeData) {
|
if (this.dataProvider.onDidChangeTreeData) {
|
||||||
this._register(this.dataProvider.onDidChangeTreeData(element => this._onDidChangeData.fire({ message: false, element })));
|
this._register(this.dataProvider.onDidChangeTreeData(element => this._onDidChangeData.fire({ message: false, element })));
|
||||||
@@ -377,6 +403,14 @@ export class ExtHostTreeView<T> extends Disposable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async onDrop(treeDataTransfer: vscode.TreeDataTransfer, targetHandleOrNode: TreeItemHandle): Promise<void> {
|
||||||
|
const target = this.getExtensionElement(targetHandleOrNode);
|
||||||
|
if (!target) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
return asPromise(() => this.dndController?.onDrop(treeDataTransfer, target));
|
||||||
|
}
|
||||||
|
|
||||||
get hasResolve(): boolean {
|
get hasResolve(): boolean {
|
||||||
return !!this.dataProvider.resolveTreeItem;
|
return !!this.dataProvider.resolveTreeItem;
|
||||||
}
|
}
|
||||||
|
|||||||
44
src/vs/workbench/api/common/shared/treeDataTransfer.ts
Normal file
44
src/vs/workbench/api/common/shared/treeDataTransfer.ts
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
/*---------------------------------------------------------------------------------------------
|
||||||
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||||
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
import { ITreeDataTransfer, ITreeDataTransferItem } from 'vs/workbench/common/views';
|
||||||
|
|
||||||
|
interface TreeDataTransferItemDTO {
|
||||||
|
asString: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface TreeDataTransferDTO {
|
||||||
|
types: string[];
|
||||||
|
items: TreeDataTransferItemDTO[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export namespace TreeDataTransferConverter {
|
||||||
|
export function toITreeDataTransfer(value: TreeDataTransferDTO): ITreeDataTransfer {
|
||||||
|
const newDataTransfer: ITreeDataTransfer = {
|
||||||
|
items: new Map<string, ITreeDataTransferItem>()
|
||||||
|
};
|
||||||
|
value.types.forEach((type, index) => {
|
||||||
|
newDataTransfer.items.set(type, {
|
||||||
|
asString: async () => value.items[index].asString
|
||||||
|
});
|
||||||
|
});
|
||||||
|
return newDataTransfer;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function toTreeDataTransferDTO(value: ITreeDataTransfer): Promise<TreeDataTransferDTO> {
|
||||||
|
const newDTO: TreeDataTransferDTO = {
|
||||||
|
types: [],
|
||||||
|
items: []
|
||||||
|
};
|
||||||
|
const entries = Array.from(value.items.entries());
|
||||||
|
for (const entry of entries) {
|
||||||
|
newDTO.types.push(entry[0]);
|
||||||
|
newDTO.items.push({
|
||||||
|
asString: await entry[1].asString()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return newDTO;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -10,7 +10,7 @@ import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
|||||||
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
|
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
|
||||||
import { MenuId, IMenuService, registerAction2, Action2 } from 'vs/platform/actions/common/actions';
|
import { MenuId, IMenuService, registerAction2, Action2 } from 'vs/platform/actions/common/actions';
|
||||||
import { IContextKeyService, ContextKeyExpr, ContextKeyEqualsExpr, RawContextKey, IContextKey } from 'vs/platform/contextkey/common/contextkey';
|
import { IContextKeyService, ContextKeyExpr, ContextKeyEqualsExpr, RawContextKey, IContextKey } from 'vs/platform/contextkey/common/contextkey';
|
||||||
import { ITreeView, ITreeViewDescriptor, IViewsRegistry, Extensions, IViewDescriptorService, ITreeItem, TreeItemCollapsibleState, ITreeViewDataProvider, TreeViewItemHandleArg, ITreeItemLabel, ViewContainer, ViewContainerLocation, ResolvableTreeItem } from 'vs/workbench/common/views';
|
import { ITreeView, ITreeViewDescriptor, IViewsRegistry, Extensions, IViewDescriptorService, ITreeItem, TreeItemCollapsibleState, ITreeViewDataProvider, TreeViewItemHandleArg, ITreeItemLabel, ViewContainer, ViewContainerLocation, ResolvableTreeItem, ITreeViewDragAndDropController, ITreeDataTransfer, TREE_ITEM_DATA_TRANSFER_TYPE } from 'vs/workbench/common/views';
|
||||||
import { IViewletViewOptions } from 'vs/workbench/browser/parts/views/viewsViewlet';
|
import { IViewletViewOptions } from 'vs/workbench/browser/parts/views/viewsViewlet';
|
||||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||||
import { IThemeService, FileThemeIcon, FolderThemeIcon, registerThemingParticipant, ThemeIcon } from 'vs/platform/theme/common/themeService';
|
import { IThemeService, FileThemeIcon, FolderThemeIcon, registerThemingParticipant, ThemeIcon } from 'vs/platform/theme/common/themeService';
|
||||||
@@ -38,7 +38,8 @@ import { textLinkForeground, textCodeBlockBackground, focusBorder, listFilterMat
|
|||||||
import { isString } from 'vs/base/common/types';
|
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 } 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 { 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';
|
||||||
@@ -55,6 +56,7 @@ import { Codicon } from 'vs/base/common/codicons';
|
|||||||
import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation';
|
import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation';
|
||||||
import { Command } from 'vs/editor/common/modes';
|
import { Command } from 'vs/editor/common/modes';
|
||||||
import { isPromiseCanceledError } from 'vs/base/common/errors';
|
import { isPromiseCanceledError } from 'vs/base/common/errors';
|
||||||
|
import { ElementsDragAndDropData } from 'vs/base/browser/ui/list/listView';
|
||||||
|
|
||||||
export class TreeViewPane extends ViewPane {
|
export class TreeViewPane extends ViewPane {
|
||||||
|
|
||||||
@@ -87,6 +89,7 @@ export class TreeViewPane extends ViewPane {
|
|||||||
if (options.titleDescription !== this.treeView.description) {
|
if (options.titleDescription !== this.treeView.description) {
|
||||||
this.updateTitleDescription(this.treeView.description);
|
this.updateTitleDescription(this.treeView.description);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.updateTreeVisibility();
|
this.updateTreeVisibility();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -237,6 +240,13 @@ export class TreeView extends Disposable implements ITreeView {
|
|||||||
get viewLocation(): ViewContainerLocation {
|
get viewLocation(): ViewContainerLocation {
|
||||||
return this.viewDescriptorService.getViewLocationById(this.id)!;
|
return this.viewDescriptorService.getViewLocationById(this.id)!;
|
||||||
}
|
}
|
||||||
|
private _dragAndDropController: ITreeViewDragAndDropController | undefined;
|
||||||
|
get dragAndDropController(): ITreeViewDragAndDropController | undefined {
|
||||||
|
return this._dragAndDropController;
|
||||||
|
}
|
||||||
|
set dragAndDropController(dnd: ITreeViewDragAndDropController | undefined) {
|
||||||
|
this._dragAndDropController = dnd;
|
||||||
|
}
|
||||||
|
|
||||||
private _dataProvider: ITreeViewDataProvider | undefined;
|
private _dataProvider: ITreeViewDataProvider | undefined;
|
||||||
get dataProvider(): ITreeViewDataProvider | undefined {
|
get dataProvider(): ITreeViewDataProvider | undefined {
|
||||||
@@ -503,6 +513,7 @@ export class TreeView extends Disposable implements ITreeView {
|
|||||||
return e.collapsibleState !== TreeItemCollapsibleState.Expanded;
|
return e.collapsibleState !== TreeItemCollapsibleState.Expanded;
|
||||||
},
|
},
|
||||||
multipleSelectionSupport: this.canSelectMany,
|
multipleSelectionSupport: this.canSelectMany,
|
||||||
|
dnd: this.dragAndDropController ? this.instantiationService.createInstance(CustomTreeViewDragAndDrop, this.dragAndDropController) : undefined,
|
||||||
overrideStyles: {
|
overrideStyles: {
|
||||||
listBackground: this.viewLocation === ViewContainerLocation.Sidebar ? SIDE_BAR_BACKGROUND : PANEL_BACKGROUND
|
listBackground: this.viewLocation === ViewContainerLocation.Sidebar ? SIDE_BAR_BACKGROUND : PANEL_BACKGROUND
|
||||||
}
|
}
|
||||||
@@ -1183,3 +1194,65 @@ export class CustomTreeView extends TreeView {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class CustomTreeViewDragAndDrop implements ITreeDragAndDrop<ITreeItem> {
|
||||||
|
constructor(private dndController: ITreeViewDragAndDropController, @ILabelService private readonly labelService: ILabelService) { }
|
||||||
|
|
||||||
|
onDragStart(data: IDragAndDropData, originalEvent: DragEvent): void {
|
||||||
|
if (originalEvent.dataTransfer) {
|
||||||
|
originalEvent.dataTransfer.setData(TREE_ITEM_DATA_TRANSFER_TYPE,
|
||||||
|
JSON.stringify((data as ElementsDragAndDropData<ITreeItem, ITreeItem[]>).getData().map(treeItem => treeItem.handle)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onDragOver(data: IDragAndDropData, targetElement: ITreeItem, targetIndex: number, originalEvent: DragEvent): boolean | ITreeDragOverReaction {
|
||||||
|
return { accept: true, bubble: TreeDragOverBubble.Down, autoExpand: true };
|
||||||
|
}
|
||||||
|
|
||||||
|
getDragURI(element: ITreeItem): string | null {
|
||||||
|
return element.resourceUri ? URI.revive(element.resourceUri).toString() : element.handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
getDragLabel?(elements: ITreeItem[]): string | undefined {
|
||||||
|
if (elements.length > 1) {
|
||||||
|
return String(elements.length);
|
||||||
|
}
|
||||||
|
const element = elements[0];
|
||||||
|
return element.label ? element.label.label : (element.resourceUri ? this.labelService.getUriLabel(URI.revive(element.resourceUri)) : undefined);
|
||||||
|
}
|
||||||
|
|
||||||
|
async drop(data: IDragAndDropData, targetNode: ITreeItem | undefined, targetIndex: number | undefined, originalEvent: DragEvent): Promise<void> {
|
||||||
|
if (!originalEvent.dataTransfer || !this.dndController || !targetNode) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const treeDataTransfer: ITreeDataTransfer = {
|
||||||
|
items: new Map()
|
||||||
|
};
|
||||||
|
let stringCount = Array.from(originalEvent.dataTransfer.items).reduce((previous, current) => {
|
||||||
|
if (current.kind === 'string') {
|
||||||
|
return previous + 1;
|
||||||
|
}
|
||||||
|
return previous;
|
||||||
|
}, 0);
|
||||||
|
await new Promise<void>(resolve => {
|
||||||
|
if (!originalEvent.dataTransfer || !this.dndController || !targetNode) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (const dataItem of originalEvent.dataTransfer.items) {
|
||||||
|
if (dataItem.kind === 'string') {
|
||||||
|
const type = dataItem.type;
|
||||||
|
dataItem.getAsString(dataValue => {
|
||||||
|
treeDataTransfer.items.set(type, {
|
||||||
|
asString: () => Promise.resolve(dataValue)
|
||||||
|
});
|
||||||
|
stringCount--;
|
||||||
|
if (stringCount === 0) {
|
||||||
|
resolve();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return this.dndController.onDrop(treeDataTransfer, targetNode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -628,10 +628,20 @@ export interface IViewDescriptorService {
|
|||||||
|
|
||||||
// Custom views
|
// Custom views
|
||||||
|
|
||||||
|
export interface ITreeDataTransferItem {
|
||||||
|
asString(): Thenable<string>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ITreeDataTransfer {
|
||||||
|
items: Map<string, ITreeDataTransferItem>;
|
||||||
|
}
|
||||||
|
|
||||||
export interface ITreeView extends IDisposable {
|
export interface ITreeView extends IDisposable {
|
||||||
|
|
||||||
dataProvider: ITreeViewDataProvider | undefined;
|
dataProvider: ITreeViewDataProvider | undefined;
|
||||||
|
|
||||||
|
dragAndDropController?: ITreeViewDragAndDropController;
|
||||||
|
|
||||||
showCollapseAllAction: boolean;
|
showCollapseAllAction: boolean;
|
||||||
|
|
||||||
canSelectMany: boolean;
|
canSelectMany: boolean;
|
||||||
@@ -814,7 +824,11 @@ export interface ITreeViewDataProvider {
|
|||||||
readonly isTreeEmpty?: boolean;
|
readonly isTreeEmpty?: boolean;
|
||||||
onDidChangeEmpty?: Event<void>;
|
onDidChangeEmpty?: Event<void>;
|
||||||
getChildren(element?: ITreeItem): Promise<ITreeItem[]>;
|
getChildren(element?: ITreeItem): Promise<ITreeItem[]>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const TREE_ITEM_DATA_TRANSFER_TYPE = 'text/treeitems';
|
||||||
|
export interface ITreeViewDragAndDropController {
|
||||||
|
onDrop(elements: ITreeDataTransfer, target: ITreeItem): Promise<void>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IEditableData {
|
export interface IEditableData {
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ suite('MainThreadHostTreeView', function () {
|
|||||||
}
|
}
|
||||||
drain(): any { return null; }
|
drain(): any { return null; }
|
||||||
}, new TestViewsService(), new TestNotificationService(), testExtensionService, new NullLogService(), undefined!);
|
}, new TestViewsService(), new TestNotificationService(), testExtensionService, new NullLogService(), undefined!);
|
||||||
mainThreadTreeViews.$registerTreeViewDataProvider(testTreeViewId, { showCollapseAll: false, canSelectMany: false });
|
mainThreadTreeViews.$registerTreeViewDataProvider(testTreeViewId, { showCollapseAll: false, canSelectMany: false, canDragAndDrop: false });
|
||||||
await testExtensionService.whenInstalledExtensionsRegistered();
|
await testExtensionService.whenInstalledExtensionsRegistered();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user