提交 4457b761 编写于 作者: S SteVen Batten

fixes #52909

上级 57ba9940
......@@ -105,6 +105,7 @@ export interface IWindowsService {
onWindowBlur: Event<number>;
onWindowMaximize: Event<number>;
onWindowUnmaximize: Event<number>;
onRecentlyOpenedChange: Event<void>;
// Dialogs
pickFileFolderAndOpen(options: INativeOpenDialogOptions): TPromise<void>;
......
......@@ -19,6 +19,7 @@ export interface IWindowsChannel extends IChannel {
call(command: 'event:onWindowOpen'): TPromise<number>;
call(command: 'event:onWindowFocus'): TPromise<number>;
call(command: 'event:onWindowBlur'): TPromise<number>;
call(command: 'event:onRecentlyOpenedChange'): TPromise<void>;
call(command: 'pickFileFolderAndOpen', arg: INativeOpenDialogOptions): TPromise<void>;
call(command: 'pickFileAndOpen', arg: INativeOpenDialogOptions): TPromise<void>;
call(command: 'pickFolderAndOpen', arg: INativeOpenDialogOptions): TPromise<void>;
......@@ -77,6 +78,7 @@ export class WindowsChannel implements IWindowsChannel {
private onWindowBlur: Event<number>;
private onWindowMaximize: Event<number>;
private onWindowUnmaximize: Event<number>;
private onRecentlyOpenedChange: Event<void>;
constructor(private service: IWindowsService) {
this.onWindowOpen = buffer(service.onWindowOpen, true);
......@@ -84,6 +86,7 @@ export class WindowsChannel implements IWindowsChannel {
this.onWindowBlur = buffer(service.onWindowBlur, true);
this.onWindowMaximize = buffer(service.onWindowMaximize, true);
this.onWindowUnmaximize = buffer(service.onWindowUnmaximize, true);
this.onRecentlyOpenedChange = buffer(service.onRecentlyOpenedChange, true);
}
call(command: string, arg?: any): TPromise<any> {
......@@ -93,6 +96,7 @@ export class WindowsChannel implements IWindowsChannel {
case 'event:onWindowBlur': return eventToCall(this.onWindowBlur);
case 'event:onWindowMaximize': return eventToCall(this.onWindowMaximize);
case 'event:onWindowUnmaximize': return eventToCall(this.onWindowUnmaximize);
case 'event:onRecentlyOpenedChange': return eventToCall(this.onRecentlyOpenedChange);
case 'pickFileFolderAndOpen': return this.service.pickFileFolderAndOpen(arg);
case 'pickFileAndOpen': return this.service.pickFileAndOpen(arg);
case 'pickFolderAndOpen': return this.service.pickFolderAndOpen(arg);
......@@ -181,6 +185,9 @@ export class WindowsChannelClient implements IWindowsService {
private _onWindowUnmaximize: Event<number> = eventFromCall<number>(this.channel, 'event:onWindowUnmaximize');
get onWindowUnmaximize(): Event<number> { return this._onWindowUnmaximize; }
private _onRecentlyOpenedChange: Event<void> = eventFromCall<void>(this.channel, 'event:onRecentlyOpenedChange');
get onRecentlyOpenedChange(): Event<void> { return this._onRecentlyOpenedChange; }
pickFileFolderAndOpen(options: INativeOpenDialogOptions): TPromise<void> {
return this.channel.call('pickFileFolderAndOpen', options);
}
......
......@@ -42,6 +42,8 @@ export class WindowsService implements IWindowsService, IURLHandler, IDisposable
readonly onWindowMaximize: Event<number> = filterEvent(fromNodeEventEmitter(app, 'browser-window-maximize', (_, w: Electron.BrowserWindow) => w.id), id => !!this.windowsMainService.getWindowById(id));
readonly onWindowUnmaximize: Event<number> = filterEvent(fromNodeEventEmitter(app, 'browser-window-unmaximize', (_, w: Electron.BrowserWindow) => w.id), id => !!this.windowsMainService.getWindowById(id));
readonly onRecentlyOpenedChange: Event<void> = this.historyService.onRecentlyOpenedChange;
constructor(
private sharedProcess: ISharedProcess,
@IWindowsMainService private windowsMainService: IWindowsMainService,
......
......@@ -13,9 +13,9 @@ import { Part } from 'vs/workbench/browser/part';
import { IMenubarService, IMenubarMenu, IMenubarMenuItemAction, IMenubarData } from 'vs/platform/menubar/common/menubar';
import { IMenuService, MenuId, IMenu, SubmenuItemAction } from 'vs/platform/actions/common/actions';
import { IThemeService } from 'vs/platform/theme/common/themeService';
import { IWindowService, MenuBarVisibility } from 'vs/platform/windows/common/windows';
import { IWindowService, MenuBarVisibility, IWindowsService } from 'vs/platform/windows/common/windows';
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { ActionRunner, IActionRunner, IAction } from 'vs/base/common/actions';
import { ActionRunner, IActionRunner, IAction, Action } from 'vs/base/common/actions';
import { Builder, $ } from 'vs/base/browser/builder';
import { Separator } from 'vs/base/browser/ui/actionbar/actionbar';
import { EventType, Dimension, toggleClass } from 'vs/base/browser/dom';
......@@ -30,6 +30,10 @@ import { Color } from 'vs/base/common/color';
import { Event, Emitter } from 'vs/base/common/event';
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
import { domEvent } from 'vs/base/browser/event';
import { IRecentlyOpened } from 'vs/platform/history/common/history';
import { IWorkspaceIdentifier, ISingleFolderWorkspaceIdentifier, isSingleFolderWorkspaceIdentifier, getWorkspaceLabel } from 'vs/platform/workspaces/common/workspaces';
import { getPathLabel } from 'vs/base/common/labels';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
interface CustomMenu {
title: string;
......@@ -86,6 +90,7 @@ export class MenubarPart extends Part {
private actionRunner: IActionRunner;
private container: Builder;
private recentlyOpened: IRecentlyOpened;
private _modifierKeyStatus: IModifierKeyStatus;
private _isFocused: boolean;
private _onVisibilityChange: Emitter<Dimension>;
......@@ -98,15 +103,19 @@ export class MenubarPart extends Part {
menubarFontSize?: number;
} = {};
private static MAX_MENU_RECENT_ENTRIES = 5;
constructor(
id: string,
@IThemeService themeService: IThemeService,
@IMenubarService private menubarService: IMenubarService,
@IMenuService private menuService: IMenuService,
@IWindowService private windowService: IWindowService,
@IWindowsService private windowsService: IWindowsService,
@IContextKeyService private contextKeyService: IContextKeyService,
@IKeybindingService private keybindingService: IKeybindingService,
@IConfigurationService private configurationService: IConfigurationService
@IConfigurationService private configurationService: IConfigurationService,
@IEnvironmentService private environmentService: IEnvironmentService
) {
super(id, { hasTitle: false }, themeService);
......@@ -144,6 +153,10 @@ export class MenubarPart extends Part {
this.isFocused = false;
this.windowService.getRecentlyOpened().then((recentlyOpened) => {
this.recentlyOpened = recentlyOpened;
});
this.registerListeners();
}
......@@ -253,6 +266,13 @@ export class MenubarPart extends Part {
}
}
private onRecentlyOpenedChange(): void {
this.windowService.getRecentlyOpened().then(recentlyOpened => {
this.recentlyOpened = recentlyOpened;
this.setupMenubar();
});
}
private registerListeners(): void {
browser.onDidChangeFullscreen(() => this.onDidChangeFullscreen());
......@@ -262,6 +282,9 @@ export class MenubarPart extends Part {
// Listen to update service
// this.updateService.onStateChange(() => this.setupMenubar());
// Listen for changes in recently opened menu
this.windowsService.onRecentlyOpenedChange(() => { this.onRecentlyOpenedChange(); });
// Listen to keybindings change
this.keybindingService.onDidUpdateKeybindings(() => this.setupMenubar());
......@@ -342,6 +365,68 @@ export class MenubarPart extends Part {
return this.currentEnableMenuBarMnemonics ? label : label.replace(/&&(.)/g, '$1');
}
private createOpenRecentMenuAction(workspace: IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier | string, commandId: string, isFile: boolean): IAction {
let label: string;
let path: string;
if (isSingleFolderWorkspaceIdentifier(workspace) || typeof workspace === 'string') {
label = getPathLabel(workspace, this.environmentService);
path = workspace;
} else {
label = getWorkspaceLabel(workspace, this.environmentService, { verbose: true });
path = workspace.configPath;
}
return new Action(commandId, label, undefined, undefined, (event) => {
const openInNewWindow = event && ((!isMacintosh && (event.ctrlKey || event.shiftKey)) || (isMacintosh && (event.metaKey || event.altKey)));
return this.windowService.openWindow([path], {
forceNewWindow: openInNewWindow,
forceOpenWorkspaceAsFile: isFile
});
});
}
private getOpenRecentActions(): IAction[] {
if (!this.recentlyOpened) {
return [];
}
const { workspaces, files } = this.recentlyOpened;
const result: IAction[] = [];
if (workspaces.length > 0) {
for (let i = 0; i < MenubarPart.MAX_MENU_RECENT_ENTRIES && i < workspaces.length; i++) {
result.push(this.createOpenRecentMenuAction(workspaces[i], 'openRecentWorkspace', false));
}
result.push(new Separator());
}
if (files.length > 0) {
for (let i = 0; i < MenubarPart.MAX_MENU_RECENT_ENTRIES && i < files.length; i++) {
result.push(this.createOpenRecentMenuAction(files[i], 'openRecentFile', false));
}
result.push(new Separator());
}
return result;
}
private insertActionsBefore(nextAction: IAction, target: IAction[]): void {
switch (nextAction.id) {
case 'workbench.action.openRecent':
target.push(...this.getOpenRecentActions());
break;
default:
break;
}
}
private setupCustomMenubar(): void {
this.container.empty();
this.container.attr('role', 'menubar');
......@@ -381,6 +466,7 @@ export class MenubarPart extends Part {
const [, actions] = group;
for (let action of actions) {
this.insertActionsBefore(action, target);
if (action instanceof SubmenuItemAction) {
const submenu = this.menuService.createMenu(action.item.submenu, this.contextKeyService);
const submenuActions = [];
......
......@@ -1123,6 +1123,7 @@ export class TestWindowsService implements IWindowsService {
onWindowBlur: Event<number>;
onWindowMaximize: Event<number>;
onWindowUnmaximize: Event<number>;
onRecentlyOpenedChange: Event<void>;
isFocused(windowId: number): TPromise<boolean> {
return TPromise.as(false);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册