Skip to content

Commit 21ae452

Browse files
authored
focused element and selected elements as arguments for title commands (microsoft#158916)
1 parent c27c163 commit 21ae452

File tree

7 files changed

+58
-14
lines changed

7 files changed

+58
-14
lines changed

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,7 @@ export class MainThreadTreeViews extends Disposable implements MainThreadTreeVie
168168
this._register(treeView.onDidExpandItem(item => this._proxy.$setExpanded(treeViewId, item.handle, true)));
169169
this._register(treeView.onDidCollapseItem(item => this._proxy.$setExpanded(treeViewId, item.handle, false)));
170170
this._register(treeView.onDidChangeSelection(items => this._proxy.$setSelection(treeViewId, items.map(({ handle }) => handle))));
171+
this._register(treeView.onDidChangeFocus(item => this._proxy.$setFocus(treeViewId, item.handle)));
171172
this._register(treeView.onDidChangeVisibility(isVisible => this._proxy.$setVisible(treeViewId, isVisible)));
172173
}
173174

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1406,6 +1406,7 @@ export interface ExtHostTreeViewsShape {
14061406
$handleDrag(sourceViewId: string, sourceTreeItemHandles: string[], operationUuid: string, token: CancellationToken): Promise<DataTransferDTO | undefined>;
14071407
$setExpanded(treeViewId: string, treeItemHandle: string, expanded: boolean): void;
14081408
$setSelection(treeViewId: string, treeItemHandles: string[]): void;
1409+
$setFocus(treeViewId: string, treeItemHandle: string): void;
14091410
$setVisible(treeViewId: string, visible: boolean): void;
14101411
$hasResolve(treeViewId: string): Promise<boolean>;
14111412
$resolve(treeViewId: string, treeItemHandle: string, token: CancellationToken): Promise<ITreeItem | undefined>;

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

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ export class ExtHostTreeViews implements ExtHostTreeViewsShape {
5959
) {
6060

6161
function isTreeViewConvertableItem(arg: any): boolean {
62-
return arg && arg.$treeViewId && (arg.$treeItemHandle || arg.$selectedTreeItems);
62+
return arg && arg.$treeViewId && (arg.$treeItemHandle || arg.$selectedTreeItems || arg.$focusedTreeItem);
6363
}
6464
commands.registerArgumentProcessor({
6565
processArgument: arg => {
@@ -221,6 +221,14 @@ export class ExtHostTreeViews implements ExtHostTreeViewsShape {
221221
treeView.setSelection(treeItemHandles);
222222
}
223223

224+
$setFocus(treeViewId: string, treeItemHandles: string) {
225+
const treeView = this.treeViews.get(treeViewId);
226+
if (!treeView) {
227+
throw new Error(localize('treeView.notRegistered', 'No tree view with id \'{0}\' registered.', treeViewId));
228+
}
229+
treeView.setFocus(treeItemHandles);
230+
}
231+
224232
$setVisible(treeViewId: string, isVisible: boolean): void {
225233
const treeView = this.treeViews.get(treeViewId);
226234
if (!treeView) {
@@ -240,8 +248,8 @@ export class ExtHostTreeViews implements ExtHostTreeViewsShape {
240248
if (treeView && '$treeItemHandle' in arg) {
241249
return treeView.getExtensionElement(arg.$treeItemHandle);
242250
}
243-
if (treeView && '$selectedTreeItems' in arg && arg.$selectedTreeItems) {
244-
return { selectedTreeItems: treeView.selectedElements };
251+
if (treeView && '$focusedTreeItem' in arg && arg.$focusedTreeItem) {
252+
return treeView.focusedElement;
245253
}
246254
return null;
247255
}
@@ -276,6 +284,9 @@ class ExtHostTreeView<T> extends Disposable {
276284
private _selectedHandles: TreeItemHandle[] = [];
277285
get selectedElements(): T[] { return <T[]>this._selectedHandles.map(handle => this.getExtensionElement(handle)).filter(element => !isUndefinedOrNull(element)); }
278286

287+
private _focusedHandle: TreeItemHandle | undefined = undefined;
288+
get focusedElement(): T | undefined { return <T | undefined>(this._focusedHandle ? this.getExtensionElement(this._focusedHandle) : undefined); }
289+
279290
private _onDidExpandElement: Emitter<vscode.TreeViewExpansionEvent<T>> = this._register(new Emitter<vscode.TreeViewExpansionEvent<T>>());
280291
readonly onDidExpandElement: Event<vscode.TreeViewExpansionEvent<T>> = this._onDidExpandElement.event;
281292

@@ -455,6 +466,10 @@ class ExtHostTreeView<T> extends Disposable {
455466
}
456467
}
457468

469+
setFocus(treeItemHandle: TreeItemHandle) {
470+
this._focusedHandle = treeItemHandle;
471+
}
472+
458473
setVisible(visible: boolean): void {
459474
if (visible !== this._visible) {
460475
this._visible = visible;

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

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ export class TreeViewPane extends ViewPane {
7171

7272
protected readonly treeView: ITreeView;
7373
private _container: HTMLElement | undefined;
74+
private _actionRunner: MultipleSelectionActionRunner;
7475

7576
constructor(
7677
options: IViewletViewOptions,
@@ -83,6 +84,7 @@ export class TreeViewPane extends ViewPane {
8384
@IOpenerService openerService: IOpenerService,
8485
@IThemeService themeService: IThemeService,
8586
@ITelemetryService telemetryService: ITelemetryService,
87+
@INotificationService notificationService: INotificationService
8688
) {
8789
super({ ...(options as IViewPaneOptions), titleMenuId: MenuId.ViewTitle, donotForwardArgs: false }, keybindingService, contextMenuService, configurationService, contextKeyService, viewDescriptorService, instantiationService, openerService, themeService, telemetryService);
8890
const { treeView } = (<ITreeViewDescriptor>Registry.as<IViewsRegistry>(Extensions.ViewsRegistry).getView(options.id));
@@ -103,6 +105,7 @@ export class TreeViewPane extends ViewPane {
103105
if (options.titleDescription !== this.treeView.description) {
104106
this.updateTitleDescription(this.treeView.description);
105107
}
108+
this._actionRunner = new MultipleSelectionActionRunner(notificationService, () => this.treeView.getSelection());
106109

107110
this.updateTreeVisibility();
108111
}
@@ -143,11 +146,12 @@ export class TreeViewPane extends ViewPane {
143146
this.treeView.setVisibility(this.isBodyVisible());
144147
}
145148

149+
override getActionRunner() {
150+
return this._actionRunner;
151+
}
152+
146153
override getActionsContext(): TreeViewPaneHandleArg {
147-
return {
148-
$selectedTreeItems: true,
149-
$treeViewId: this.id
150-
};
154+
return { $treeViewId: this.id, $focusedTreeItem: true, $selectedTreeItems: true };
151155
}
152156

153157
}
@@ -214,6 +218,9 @@ abstract class AbstractTreeView extends Disposable implements ITreeView {
214218
private _onDidChangeSelection: Emitter<ITreeItem[]> = this._register(new Emitter<ITreeItem[]>());
215219
readonly onDidChangeSelection: Event<ITreeItem[]> = this._onDidChangeSelection.event;
216220

221+
private _onDidChangeFocus: Emitter<ITreeItem> = this._register(new Emitter<ITreeItem>());
222+
readonly onDidChangeFocus: Event<ITreeItem> = this._onDidChangeFocus.event;
223+
217224
private readonly _onDidChangeVisibility: Emitter<boolean> = this._register(new Emitter<boolean>());
218225
readonly onDidChangeVisibility: Event<boolean> = this._onDidChangeVisibility.event;
219226

@@ -617,6 +624,11 @@ abstract class AbstractTreeView extends Disposable implements ITreeView {
617624
customTreeKey.set(true);
618625
this._register(this.tree.onContextMenu(e => this.onContextMenu(treeMenus, e, actionRunner)));
619626
this._register(this.tree.onDidChangeSelection(e => this._onDidChangeSelection.fire(e.elements)));
627+
this._register(this.tree.onDidChangeFocus(e => {
628+
if (e.elements.length) {
629+
this._onDidChangeFocus.fire(e.elements[0]);
630+
}
631+
}));
620632
this._register(this.tree.onDidChangeCollapseState(e => {
621633
if (!e.node.element) {
622634
return;
@@ -803,6 +815,10 @@ abstract class AbstractTreeView extends Disposable implements ITreeView {
803815
this.tree?.setSelection(items);
804816
}
805817

818+
getSelection(): ITreeItem[] {
819+
return this.tree?.getSelection() ?? [];
820+
}
821+
806822
setFocus(item: ITreeItem): void {
807823
if (this.tree) {
808824
this.focus(true, item);
@@ -1234,13 +1250,13 @@ class MultipleSelectionActionRunner extends ActionRunner {
12341250
}));
12351251
}
12361252

1237-
override async runAction(action: IAction, context: TreeViewItemHandleArg): Promise<void> {
1253+
override async runAction(action: IAction, context: TreeViewItemHandleArg | TreeViewPaneHandleArg): Promise<void> {
12381254
const selection = this.getSelectedResources();
12391255
let selectionHandleArgs: TreeViewItemHandleArg[] | undefined = undefined;
12401256
let actionInSelected: boolean = false;
12411257
if (selection.length > 1) {
12421258
selectionHandleArgs = selection.map(selected => {
1243-
if (selected.handle === context.$treeItemHandle) {
1259+
if ((selected.handle === (context as TreeViewItemHandleArg).$treeItemHandle) || (context as TreeViewPaneHandleArg).$selectedTreeItems) {
12441260
actionInSelected = true;
12451261
}
12461262
return { $treeViewId: context.$treeViewId, $treeItemHandle: selected.handle };

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

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import { attachButtonStyler, attachProgressBarStyler } from 'vs/platform/theme/c
1111
import { PANEL_BACKGROUND, SIDE_BAR_BACKGROUND } from 'vs/workbench/common/theme';
1212
import { after, append, $, trackFocus, EventType, addDisposableListener, createCSSRule, asCSSUrl } from 'vs/base/browser/dom';
1313
import { IDisposable, Disposable, DisposableStore } from 'vs/base/common/lifecycle';
14-
import { IAction } from 'vs/base/common/actions';
14+
import { IAction, IActionRunner } from 'vs/base/common/actions';
1515
import { ActionsOrientation, IActionViewItem, prepareActions } from 'vs/base/browser/ui/actionbar/actionbar';
1616
import { Registry } from 'vs/platform/registry/common/platform';
1717
import { ToolBar } from 'vs/base/browser/ui/toolbar/toolbar';
@@ -298,7 +298,8 @@ export abstract class ViewPane extends Pane implements IView {
298298
actionViewItemProvider: action => this.getActionViewItem(action),
299299
ariaLabel: nls.localize('viewToolbarAriaLabel', "{0} actions", this.title),
300300
getKeyBinding: action => this.keybindingService.lookupKeybinding(action.id),
301-
renderDropdownAsChildElement: true
301+
renderDropdownAsChildElement: true,
302+
actionRunner: this.getActionRunner()
302303
});
303304

304305
this._register(this.toolbar);
@@ -519,6 +520,10 @@ export abstract class ViewPane extends Pane implements IView {
519520
return undefined;
520521
}
521522

523+
getActionRunner(): IActionRunner | undefined {
524+
return undefined;
525+
}
526+
522527
getOptimalWidth(): number {
523528
return 0;
524529
}

src/vs/workbench/common/views.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -663,6 +663,8 @@ export interface ITreeView extends IDisposable {
663663

664664
readonly onDidChangeSelection: Event<ITreeItem[]>;
665665

666+
readonly onDidChangeFocus: Event<ITreeItem>;
667+
666668
readonly onDidChangeVisibility: Event<boolean>;
667669

668670
readonly onDidChangeActions: Event<void>;
@@ -691,6 +693,8 @@ export interface ITreeView extends IDisposable {
691693

692694
setSelection(items: ITreeItem[]): void;
693695

696+
getSelection(): ITreeItem[];
697+
694698
setFocus(item: ITreeItem): void;
695699

696700
show(container: any): void;
@@ -712,7 +716,8 @@ export interface ITreeViewDescriptor extends IViewDescriptor {
712716

713717
export type TreeViewPaneHandleArg = {
714718
$treeViewId: string;
715-
$selectedTreeItems: boolean;
719+
$selectedTreeItems?: boolean;
720+
$focusedTreeItem?: boolean;
716721
};
717722

718723
export type TreeViewItemHandleArg = {

src/vs/workbench/contrib/userDataSync/browser/userDataSyncMergesView.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ import { IEditorContribution } from 'vs/editor/common/editorCommon';
3636
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
3737
import { FloatingClickWidget } from 'vs/workbench/browser/codeeditor';
3838
import { registerEditorContribution } from 'vs/editor/browser/editorExtensions';
39-
import { Severity } from 'vs/platform/notification/common/notification';
39+
import { INotificationService, Severity } from 'vs/platform/notification/common/notification';
4040
import { IDialogService } from 'vs/platform/dialogs/common/dialogs';
4141
import { DEFAULT_EDITOR_ASSOCIATION } from 'vs/workbench/common/editor';
4242

@@ -66,8 +66,9 @@ export class UserDataSyncMergesViewPane extends TreeViewPane {
6666
@IOpenerService openerService: IOpenerService,
6767
@IThemeService themeService: IThemeService,
6868
@ITelemetryService telemetryService: ITelemetryService,
69+
@INotificationService notificationService: INotificationService
6970
) {
70-
super(options, keybindingService, contextMenuService, configurationService, contextKeyService, viewDescriptorService, instantiationService, openerService, themeService, telemetryService);
71+
super(options, keybindingService, contextMenuService, configurationService, contextKeyService, viewDescriptorService, instantiationService, openerService, themeService, telemetryService, notificationService);
7172
this.userDataSyncPreview = userDataSyncWorkbenchService.userDataSyncPreview;
7273

7374
this._register(this.userDataSyncPreview.onDidChangeResources(() => this.updateSyncButtonEnablement()));

0 commit comments

Comments
 (0)