Skip to content

Commit

Permalink
contextMenuService.onDidContextMenu
Browse files Browse the repository at this point in the history
fixes #41157
  • Loading branch information
isidorn committed Jan 8, 2018
1 parent 94b5920 commit 538db06
Show file tree
Hide file tree
Showing 13 changed files with 69 additions and 35 deletions.
29 changes: 20 additions & 9 deletions src/vs/platform/actions/browser/menuItemActionItem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,19 +15,23 @@ import { IDisposable, dispose } from 'vs/base/common/lifecycle';
import { ActionItem, Separator } from 'vs/base/browser/ui/actionbar/actionbar';
import { domEvent } from 'vs/base/browser/event';
import { Emitter } from 'vs/base/common/event';
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
import { memoize } from 'vs/base/common/decorators';

const _altKey = new class extends Emitter<boolean> {
class AltKeyEmitter extends Emitter<boolean> {

private _subscriptions: IDisposable[] = [];
private _isPressed: boolean;

constructor() {
private constructor(contextMenuService: IContextMenuService) {
super();

this._subscriptions.push(domEvent(document.body, 'keydown')(e => this.isPressed = e.altKey));
this._subscriptions.push(domEvent(document.body, 'keyup')(e => this.isPressed = false));
this._subscriptions.push(domEvent(document.body, 'mouseleave')(e => this.isPressed = false));
this._subscriptions.push(domEvent(document.body, 'blur')(e => this.isPressed = false));
// Workaround since we do not get any events while a context menu is shown
this._subscriptions.push(contextMenuService.onDidContextMenu(() => this.isPressed = false));
}

get isPressed(): boolean {
Expand All @@ -39,21 +43,27 @@ const _altKey = new class extends Emitter<boolean> {
this.fire(this._isPressed);
}

@memoize
static getInstance(contextMenuService: IContextMenuService) {
return new AltKeyEmitter(contextMenuService);
}

dispose() {
super.dispose();
this._subscriptions = dispose(this._subscriptions);
}
};
}

export function fillInActions(menu: IMenu, options: IMenuActionOptions, target: IAction[] | { primary: IAction[]; secondary: IAction[]; }, isPrimaryGroup: (group: string) => boolean = group => group === 'navigation'): void {
export function fillInActions(menu: IMenu, options: IMenuActionOptions, target: IAction[] | { primary: IAction[]; secondary: IAction[]; }, contextMenuService: IContextMenuService, isPrimaryGroup: (group: string) => boolean = group => group === 'navigation'): void {
const groups = menu.getActions(options);
if (groups.length === 0) {
return;
}
const altKey = AltKeyEmitter.getInstance(contextMenuService);

for (let tuple of groups) {
let [group, actions] = tuple;
if (_altKey.isPressed) {
if (altKey.isPressed) {
actions = actions.map(a => !!a.alt ? a.alt : a);
}

Expand Down Expand Up @@ -97,9 +107,9 @@ export function fillInActions(menu: IMenu, options: IMenuActionOptions, target:
}


export function createActionItem(action: IAction, keybindingService: IKeybindingService, messageService: IMessageService): ActionItem {
export function createActionItem(action: IAction, keybindingService: IKeybindingService, messageService: IMessageService, contextMenuService: IContextMenuService): ActionItem {
if (action instanceof MenuItemAction) {
return new MenuItemActionItem(action, keybindingService, messageService);
return new MenuItemActionItem(action, keybindingService, messageService, contextMenuService);
}
return undefined;
}
Expand All @@ -111,7 +121,8 @@ export class MenuItemActionItem extends ActionItem {
constructor(
action: MenuItemAction,
@IKeybindingService private _keybindingService: IKeybindingService,
@IMessageService protected _messageService: IMessageService
@IMessageService protected _messageService: IMessageService,
@IContextMenuService private _contextMenuService: IContextMenuService
) {
super(undefined, action, { icon: !!action.class, label: !action.class });
}
Expand Down Expand Up @@ -144,7 +155,7 @@ export class MenuItemActionItem extends ActionItem {
}
};

this._callOnDispose.push(_altKey.event(value => {
this._callOnDispose.push(AltKeyEmitter.getInstance(this._contextMenuService).event(value => {
altDown = value;
updateAltState();
}));
Expand Down
10 changes: 9 additions & 1 deletion src/vs/platform/contextview/browser/contextMenuService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,14 @@ import { ContextMenuHandler } from './contextMenuHandler';
import { IContextViewService, IContextMenuService, IContextMenuDelegate } from './contextView';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { IMessageService } from 'vs/platform/message/common/message';
import Event, { Emitter } from 'vs/base/common/event';


export class ContextMenuService implements IContextMenuService {
public _serviceBrand: any;

private contextMenuHandler: ContextMenuHandler;
private _onDidContextMenu = new Emitter<void>();

constructor(container: HTMLElement, telemetryService: ITelemetryService, messageService: IMessageService, contextViewService: IContextViewService) {
this.contextMenuHandler = new ContextMenuHandler(container, contextViewService, telemetryService, messageService);
Expand All @@ -30,5 +33,10 @@ export class ContextMenuService implements IContextMenuService {

public showContextMenu(delegate: IContextMenuDelegate): void {
this.contextMenuHandler.showContextMenu(delegate);
this._onDidContextMenu.fire();
}

public get onDidContextMenu(): Event<void> {
return this._onDidContextMenu.event;
}
}
}
5 changes: 4 additions & 1 deletion src/vs/platform/contextview/browser/contextView.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { IDisposable } from 'vs/base/common/lifecycle';
import { IAction, IActionRunner, Action } from 'vs/base/common/actions';
import { IActionItem } from 'vs/base/browser/ui/actionbar/actionbar';
import { TPromise } from 'vs/base/common/winjs.base';
import Event from 'vs/base/common/event';
import { ResolvedKeybinding } from 'vs/base/common/keyCodes';
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';

Expand All @@ -24,7 +25,7 @@ export interface IContextViewDelegate {
getAnchor(): HTMLElement | { x: number; y: number; };
render(container: HTMLElement): IDisposable;
canRelayout?: boolean; // Default: true
onDOMEvent?(e: Event, activeElement: HTMLElement): void;
onDOMEvent?(e: any, activeElement: HTMLElement): void;
onHide?(data?: any): void;
}

Expand All @@ -33,6 +34,8 @@ export const IContextMenuService = createDecorator<IContextMenuService>('context
export interface IContextMenuService {
_serviceBrand: any;
showContextMenu(delegate: IContextMenuDelegate): void;
// TODO@isidor these event should be removed once we get async context menus
onDidContextMenu: Event<void>;
}

export interface IEvent {
Expand Down
6 changes: 3 additions & 3 deletions src/vs/workbench/browser/parts/editor/titleControl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -270,7 +270,7 @@ export abstract class TitleControl extends Themable implements ITitleAreaControl

// Check extensions
if (!actionItem) {
actionItem = createActionItem(action, this.keybindingService, this.messageService);
actionItem = createActionItem(action, this.keybindingService, this.messageService, this.contextMenuService);
}

return actionItem;
Expand Down Expand Up @@ -310,7 +310,7 @@ export abstract class TitleControl extends Themable implements ITitleAreaControl
const titleBarMenu = this.menuService.createMenu(MenuId.EditorTitle, scopedContextKeyService);
this.disposeOnEditorActions.push(titleBarMenu, titleBarMenu.onDidChange(_ => this.update()));

fillInActions(titleBarMenu, { arg: this.resourceContext.get() }, { primary, secondary });
fillInActions(titleBarMenu, { arg: this.resourceContext.get() }, { primary, secondary }, this.contextMenuService);
}

return { primary, secondary };
Expand Down Expand Up @@ -386,7 +386,7 @@ export abstract class TitleControl extends Themable implements ITitleAreaControl

// Fill in contributed actions
const actions: IAction[] = [];
fillInActions(this.contextMenu, { shouldForwardArgs: true, arg: this.resourceContext.get() }, actions);
fillInActions(this.contextMenu, { shouldForwardArgs: true, arg: this.resourceContext.get() }, actions, this.contextMenuService);

// Show it
this.contextMenuService.showContextMenu({
Expand Down
11 changes: 6 additions & 5 deletions src/vs/workbench/browser/parts/views/treeView.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ export class TreeView extends TreeViewsViewletPanel {
}

getActionItem(action: IAction): IActionItem {
return createActionItem(action, this.keybindingService, this.messageService);
return createActionItem(action, this.keybindingService, this.messageService, this.contextMenuService);
}

private setInput(): TPromise<void> {
Expand Down Expand Up @@ -400,7 +400,8 @@ class Menus implements IDisposable {
constructor(
private id: string,
@IContextKeyService private contextKeyService: IContextKeyService,
@IMenuService private menuService: IMenuService
@IMenuService private menuService: IMenuService,
@IContextMenuService private contextMenuService: IContextMenuService
) {
if (this.titleDisposable) {
this.titleDisposable.dispose();
Expand All @@ -414,7 +415,7 @@ class Menus implements IDisposable {
const updateActions = () => {
this.titleActions = [];
this.titleSecondaryActions = [];
fillInActions(titleMenu, null, { primary: this.titleActions, secondary: this.titleSecondaryActions });
fillInActions(titleMenu, null, { primary: this.titleActions, secondary: this.titleSecondaryActions }, this.contextMenuService);
this._onDidChangeTitle.fire();
};

Expand Down Expand Up @@ -451,7 +452,7 @@ class Menus implements IDisposable {
const primary: IAction[] = [];
const secondary: IAction[] = [];
const result = { primary, secondary };
fillInActions(menu, { shouldForwardArgs: true }, result);
fillInActions(menu, { shouldForwardArgs: true }, result, this.contextMenuService);

menu.dispose();
contextKeyService.dispose();
Expand All @@ -462,4 +463,4 @@ class Menus implements IDisposable {
dispose(): void {
this.disposables = dispose(this.disposables);
}
}
}
2 changes: 1 addition & 1 deletion src/vs/workbench/electron-browser/window.ts
Original file line number Diff line number Diff line change
Expand Up @@ -376,7 +376,7 @@ export class ElectronWindow extends Themable {
const actions: (MenuItemAction | Separator)[] = [];

// Fill actions into groups respecting order
fillInActions(this.touchBarMenu, void 0, actions);
fillInActions(this.touchBarMenu, void 0, actions, this.contextMenuService);

// Convert into command action multi array
const items: ICommandAction[][] = [];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,7 @@ export class BaseDebugController extends DefaultController {
this.contextMenuService.showContextMenu({
getAnchor: () => anchor,
getActions: () => this.actionProvider.getSecondaryActions(tree, element).then(actions => {
fillInActions(this.contributedContextMenu, { arg: this.getContext(element) }, actions);
fillInActions(this.contributedContextMenu, { arg: this.getContext(element) }, actions, this.contextMenuService);
return actions;
}),
onHide: (wasCancelled?: boolean) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -424,7 +424,7 @@ export class FileController extends DefaultController implements IDisposable {
getAnchor: () => anchor,
getActions: () => {
const actions = [];
fillInActions(this.contributedContextMenu, { arg: stat instanceof FileStat ? stat.resource : undefined, shouldForwardArgs: true }, actions);
fillInActions(this.contributedContextMenu, { arg: stat instanceof FileStat ? stat.resource : undefined, shouldForwardArgs: true }, actions, this.contextMenuService);
return TPromise.as(actions);
},
onHide: (wasCancelled?: boolean) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -290,7 +290,7 @@ export class OpenEditorsView extends ViewsViewletPanel {
getAnchor: () => e.anchor,
getActions: () => {
const actions = [];
fillInActions(this.contributedContextMenu, { shouldForwardArgs: true, arg: element instanceof OpenEditor ? element.editorInput.getResource() : undefined }, actions);
fillInActions(this.contributedContextMenu, { shouldForwardArgs: true, arg: element instanceof OpenEditor ? element.editorInput.getResource() : undefined }, actions, this.contextMenuService);
return TPromise.as(actions);
},
getActionsContext: () => element instanceof OpenEditor ? { group: element.editorGroup, editor: element.editorInput } : { group: element }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ import { sortedDiff, firstIndex } from 'vs/base/common/arrays';
import { IMarginData } from 'vs/editor/browser/controller/mouseTarget';
import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';
import { ISplice } from 'vs/base/common/sequence';
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';

// TODO@Joao
// Need to subclass MenuItemActionItem in order to respect
Expand Down Expand Up @@ -197,7 +198,8 @@ class DirtyDiffWidget extends PeekViewWidget {
@IMenuService menuService: IMenuService,
@IKeybindingService private keybindingService: IKeybindingService,
@IMessageService private messageService: IMessageService,
@IContextKeyService contextKeyService: IContextKeyService
@IContextKeyService contextKeyService: IContextKeyService,
@IContextMenuService private contextMenuService: IContextMenuService
) {
super(editor, { isResizeable: true, frameWidth: 1, keepEditorSelection: true });

Expand Down Expand Up @@ -271,7 +273,7 @@ class DirtyDiffWidget extends PeekViewWidget {
this._actionbarWidget.push([previous, next], { label: false, icon: true });

const actions: IAction[] = [];
fillInActions(this.menu, { shouldForwardArgs: true }, actions);
fillInActions(this.menu, { shouldForwardArgs: true }, actions, this.contextMenuService);
this._actionbarWidget.push(actions, { label: false, icon: true });
}

Expand All @@ -288,7 +290,7 @@ class DirtyDiffWidget extends PeekViewWidget {
return undefined;
}

return new DiffMenuItemActionItem(action, this.keybindingService, this.messageService);
return new DiffMenuItemActionItem(action, this.keybindingService, this.messageService, this.contextMenuService);
}

protected _fillBody(container: HTMLElement): void {
Expand Down
10 changes: 6 additions & 4 deletions src/vs/workbench/parts/scm/electron-browser/scmMenus.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { IAction } from 'vs/base/common/actions';
import { fillInActions } from 'vs/platform/actions/browser/menuItemActionItem';
import { ISCMProvider, ISCMResource, ISCMResourceGroup } from 'vs/workbench/services/scm/common/scm';
import { getSCMResourceContextKey } from './scmUtil';
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';

export class SCMMenus implements IDisposable {

Expand All @@ -30,7 +31,8 @@ export class SCMMenus implements IDisposable {
constructor(
provider: ISCMProvider | undefined,
@IContextKeyService contextKeyService: IContextKeyService,
@IMenuService private menuService: IMenuService
@IMenuService private menuService: IMenuService,
@IContextMenuService private contextMenuService: IContextMenuService
) {
this.contextKeyService = contextKeyService.createScoped();
const scmProviderKey = this.contextKeyService.createKey<string | undefined>('scmProvider', void 0);
Expand All @@ -52,7 +54,7 @@ export class SCMMenus implements IDisposable {
this.titleActions = [];
this.titleSecondaryActions = [];
// TODO@joao: second arg used to be null
fillInActions(this.titleMenu, { shouldForwardArgs: true }, { primary: this.titleActions, secondary: this.titleSecondaryActions });
fillInActions(this.titleMenu, { shouldForwardArgs: true }, { primary: this.titleActions, secondary: this.titleSecondaryActions }, this.contextMenuService);
this._onDidChangeTitle.fire();
}

Expand Down Expand Up @@ -88,7 +90,7 @@ export class SCMMenus implements IDisposable {
const primary: IAction[] = [];
const secondary: IAction[] = [];
const result = { primary, secondary };
fillInActions(menu, { shouldForwardArgs: true }, result, g => /^inline/.test(g));
fillInActions(menu, { shouldForwardArgs: true }, result, this.contextMenuService, g => /^inline/.test(g));

menu.dispose();
contextKeyService.dispose();
Expand All @@ -99,4 +101,4 @@ export class SCMMenus implements IDisposable {
dispose(): void {
this.disposables = dispose(this.disposables);
}
}
}
10 changes: 5 additions & 5 deletions src/vs/workbench/parts/scm/electron-browser/scmViewlet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -323,7 +323,7 @@ class MainPanel extends ViewletPanel {
const secondary: IAction[] = [];
const result = { primary, secondary };

fillInActions(menu, { shouldForwardArgs: true }, result, g => g === 'inline');
fillInActions(menu, { shouldForwardArgs: true }, result, this.contextMenuService, g => g === 'inline');

menu.dispose();
contextKeyService.dispose();
Expand Down Expand Up @@ -912,7 +912,7 @@ export class RepositoryPanel extends ViewletPanel {
return undefined;
}

return new SCMMenuItemActionItem(action, this.keybindingService, this.messageService);
return new SCMMenuItemActionItem(action, this.keybindingService, this.messageService, this.contextMenuService);
}

getActionsContext(): any {
Expand Down Expand Up @@ -1028,15 +1028,15 @@ export class SCMViewlet extends PanelViewlet implements IViewModel {
@IContextKeyService contextKeyService: IContextKeyService,
@IKeybindingService protected keybindingService: IKeybindingService,
@IMessageService protected messageService: IMessageService,
@IContextMenuService contextMenuService: IContextMenuService,
@IContextMenuService private contextMenuService: IContextMenuService,
@IThemeService protected themeService: IThemeService,
@ICommandService protected commandService: ICommandService,
@IEditorGroupService protected editorGroupService: IEditorGroupService,
@IWorkbenchEditorService protected editorService: IWorkbenchEditorService,
@IWorkspaceContextService contextService: IWorkspaceContextService,
@IStorageService storageService: IStorageService,
@IExtensionService extensionService: IExtensionService,
@IConfigurationService private configurationService: IConfigurationService
@IConfigurationService private configurationService: IConfigurationService,
) {
super(VIEWLET_ID, { showHeaderInTitleWhenSingleView: true }, telemetryService, themeService);

Expand Down Expand Up @@ -1176,7 +1176,7 @@ export class SCMViewlet extends PanelViewlet implements IViewModel {
return undefined;
}

return new SCMMenuItemActionItem(action, this.keybindingService, this.messageService);
return new SCMMenuItemActionItem(action, this.keybindingService, this.messageService, this.contextMenuService);
}

layout(dimension: Dimension): void {
Expand Down

0 comments on commit 538db06

Please sign in to comment.