From 811e6c11f9033e5afc0ede77b20696e8b6e2583c Mon Sep 17 00:00:00 2001 From: Vincent Fugnitto Date: Wed, 21 Aug 2019 14:46:24 -0400 Subject: [PATCH] Implement 'more' toolbar item for the explorer Fixes #5951 Fixes #6010 - Added a new toolbar item for the `explorer` which consists of mutliple commands. - Adjusted the `WorkspaceRootUriAwareCommandHandler` to better handle commands which can be used by the workspace root in both a single and multi-root workspace. - Added the command `New File` to the toolbar item. - Added the command `New Folder` to the toolbar item. - Added the command `Add Folder to Workspace...` to the toolbar item. - Added the command `Compare With...` to the toolbar item. Signed-off-by: Vincent Fugnitto --- .../src/browser/diff/git-diff-contribution.ts | 52 +++++++++++++++--- .../browser/diff/git-diff-frontend-module.ts | 2 + .../src/browser/navigator-contribution.ts | 54 ++++++++++++++++++- .../src/browser/workspace-commands.ts | 22 ++++++-- 4 files changed, 116 insertions(+), 14 deletions(-) diff --git a/packages/git/src/browser/diff/git-diff-contribution.ts b/packages/git/src/browser/diff/git-diff-contribution.ts index 79e8b09505a76..9bef51519ff79 100644 --- a/packages/git/src/browser/diff/git-diff-contribution.ts +++ b/packages/git/src/browser/diff/git-diff-contribution.ts @@ -14,14 +14,14 @@ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 ********************************************************************************/ -import { CommandRegistry, Command, MenuModelRegistry, SelectionService, MessageService } from '@theia/core/lib/common'; +import { CommandRegistry, Command, MenuModelRegistry, SelectionService, MessageService, Mutable } from '@theia/core/lib/common'; import { FrontendApplication, AbstractViewContribution } from '@theia/core/lib/browser'; import { WidgetManager } from '@theia/core/lib/browser/widget-manager'; import { injectable, inject } from 'inversify'; import { GitDiffWidget, GIT_DIFF } from './git-diff-widget'; import { open, OpenerService } from '@theia/core/lib/browser'; -import { NavigatorContextMenu } from '@theia/navigator/lib/browser/navigator-contribution'; -import { UriCommandHandler, UriAwareCommandHandler } from '@theia/core/lib/common/uri-command-handler'; +import { NavigatorContextMenu, NavigatorMoreToolbarGroups } from '@theia/navigator/lib/browser/navigator-contribution'; +import { UriCommandHandler } from '@theia/core/lib/common/uri-command-handler'; import { GitQuickOpenService } from '../git-quick-open-service'; import { FileSystem } from '@theia/filesystem/lib/common'; import { DiffUris } from '@theia/core/lib/browser/diff-uris'; @@ -29,6 +29,10 @@ import URI from '@theia/core/lib/common/uri'; import { GIT_RESOURCE_SCHEME } from '../git-resource'; import { Git } from '../../common'; import { GitRepositoryProvider } from '../git-repository-provider'; +import { WorkspaceRootUriAwareCommandHandler } from '@theia/workspace/lib/browser/workspace-commands'; +import { WorkspaceService } from '@theia/workspace/lib/browser'; +import { TabBarToolbarContribution, TabBarToolbarRegistry, TabBarToolbarItem } from '@theia/core/lib/browser/shell/tab-bar-toolbar'; +import { FileNavigatorWidget } from '@theia/navigator/lib/browser/navigator-widget'; export namespace GitDiffCommands { export const OPEN_FILE_DIFF: Command = { @@ -39,7 +43,13 @@ export namespace GitDiffCommands { } @injectable() -export class GitDiffContribution extends AbstractViewContribution { +export class GitDiffContribution extends AbstractViewContribution implements TabBarToolbarContribution { + + @inject(CommandRegistry) + protected readonly commandRegistry: CommandRegistry; + + @inject(WorkspaceService) + protected readonly workspaceService: WorkspaceService; constructor( @inject(SelectionService) protected readonly selectionService: SelectionService, @@ -68,7 +78,7 @@ export class GitDiffContribution extends AbstractViewContribution } registerCommands(commands: CommandRegistry): void { - commands.registerCommand(GitDiffCommands.OPEN_FILE_DIFF, this.newUriAwareCommandHandler({ + commands.registerCommand(GitDiffCommands.OPEN_FILE_DIFF, this.newWorkspaceRootUriAwareCommandHandler({ isVisible: uri => !!this.repositoryProvider.findRepository(uri), isEnabled: uri => !!this.repositoryProvider.findRepository(uri), execute: async fileUri => { @@ -101,6 +111,33 @@ export class GitDiffContribution extends AbstractViewContribution })); } + registerToolbarItems(registry: TabBarToolbarRegistry): void { + // Register 'more actions...' toolbar item which consists of multiple commands. + const navigatorRegisterItem = (item: Mutable) => { + const commandId = item.command; + const id = 'navigator.tabbar.toolbar.' + commandId; + const command = this.commandRegistry.getCommand(commandId); + this.commandRegistry.registerCommand({ id, iconClass: command && command.iconClass }, { + execute: (w, ...args) => w instanceof FileNavigatorWidget + && this.commandRegistry.executeCommand(commandId, ...args), + isEnabled: (w, ...args) => w instanceof FileNavigatorWidget + && this.commandRegistry.isEnabled(commandId, ...args), + isVisible: (w, ...args) => w instanceof FileNavigatorWidget + && this.commandRegistry.isVisible(commandId, ...args), + isToggled: (w, ...args) => w instanceof FileNavigatorWidget + && this.commandRegistry.isToggled(commandId, ...args), + }); + item.command = id; + registry.registerItem(item); + }; + navigatorRegisterItem({ + id: GitDiffCommands.OPEN_FILE_DIFF.id, + command: GitDiffCommands.OPEN_FILE_DIFF.id, + tooltip: GitDiffCommands.OPEN_FILE_DIFF.label, + group: NavigatorMoreToolbarGroups.SCM, + }); + } + async showWidget(options: Git.Options.Diff): Promise { const widget = await this.widget; await widget.setContent(options); @@ -109,8 +146,7 @@ export class GitDiffContribution extends AbstractViewContribution }); } - protected newUriAwareCommandHandler(handler: UriCommandHandler): UriAwareCommandHandler { - return new UriAwareCommandHandler(this.selectionService, handler); + protected newWorkspaceRootUriAwareCommandHandler(handler: UriCommandHandler): WorkspaceRootUriAwareCommandHandler { + return new WorkspaceRootUriAwareCommandHandler(this.workspaceService, this.selectionService, handler); } - } diff --git a/packages/git/src/browser/diff/git-diff-frontend-module.ts b/packages/git/src/browser/diff/git-diff-frontend-module.ts index 9ce1e5fab418d..ac37e760d1bf8 100644 --- a/packages/git/src/browser/diff/git-diff-frontend-module.ts +++ b/packages/git/src/browser/diff/git-diff-frontend-module.ts @@ -18,6 +18,7 @@ import { interfaces } from 'inversify'; import { GitDiffContribution } from './git-diff-contribution'; import { WidgetFactory, bindViewContribution } from '@theia/core/lib/browser'; import { GitDiffWidget, GIT_DIFF } from './git-diff-widget'; +import { TabBarToolbarContribution } from '@theia/core/lib/browser/shell/tab-bar-toolbar'; import '../../../src/browser/style/diff.css'; @@ -30,5 +31,6 @@ export function bindGitDiffModule(bind: interfaces.Bind): void { })); bindViewContribution(bind, GitDiffContribution); + bind(TabBarToolbarContribution).toService(GitDiffContribution); } diff --git a/packages/navigator/src/browser/navigator-contribution.ts b/packages/navigator/src/browser/navigator-contribution.ts index d4dcc631dc6d7..2c084ec3ae843 100644 --- a/packages/navigator/src/browser/navigator-contribution.ts +++ b/packages/navigator/src/browser/navigator-contribution.ts @@ -21,7 +21,7 @@ import { OpenerService, FrontendApplicationContribution, FrontendApplication, CompositeTreeNode } from '@theia/core/lib/browser'; import { FileDownloadCommands } from '@theia/filesystem/lib/browser/download/file-download-command-contribution'; -import { CommandRegistry, MenuModelRegistry, MenuPath, isOSX, Command, DisposableCollection } from '@theia/core/lib/common'; +import { CommandRegistry, MenuModelRegistry, MenuPath, isOSX, Command, DisposableCollection, Mutable } from '@theia/core/lib/common'; import { SHELL_TABBAR_CONTEXT_MENU } from '@theia/core/lib/browser'; import { WorkspaceCommands, WorkspaceService, WorkspacePreferences } from '@theia/workspace/lib/browser'; import { FILE_NAVIGATOR_ID, FileNavigatorWidget, EXPLORER_VIEW_CONTAINER_ID } from './navigator-widget'; @@ -30,7 +30,7 @@ import { NavigatorKeybindingContexts } from './navigator-keybinding-context'; import { FileNavigatorFilter } from './navigator-filter'; import { WorkspaceNode } from './navigator-tree'; import { NavigatorContextKeyService } from './navigator-context-key-service'; -import { TabBarToolbarContribution, TabBarToolbarRegistry } from '@theia/core/lib/browser/shell/tab-bar-toolbar'; +import { TabBarToolbarContribution, TabBarToolbarRegistry, TabBarToolbarItem } from '@theia/core/lib/browser/shell/tab-bar-toolbar'; import { FileSystemCommands } from '@theia/filesystem/lib/browser/filesystem-frontend-contribution'; import { NavigatorDiff, NavigatorDiffCommands } from './navigator-diff'; import { UriSelection } from '@theia/core/lib/common/selection'; @@ -61,6 +61,16 @@ export namespace FileNavigatorCommands { }; } +/** + * Navigator `More Actions...` toolbar item groups. + * Used in order to group items present in the toolbar. + */ +export namespace NavigatorMoreToolbarGroups { + export const NEW_OPEN = '1_navigator_new_open'; + export const WORKSPACE = '2_navigator_workspace'; + export const SCM = '3_navigator_scm'; +} + export const NAVIGATOR_CONTEXT_MENU: MenuPath = ['navigator-context-menu']; /** @@ -95,6 +105,9 @@ export namespace NavigatorContextMenu { @injectable() export class FileNavigatorContribution extends AbstractViewContribution implements FrontendApplicationContribution, TabBarToolbarContribution { + @inject(CommandRegistry) + protected readonly commandRegistry: CommandRegistry; + @inject(NavigatorContextKeyService) protected readonly contextKeyService: NavigatorContextKeyService; @@ -340,6 +353,43 @@ export class FileNavigatorContribution extends AbstractViewContribution) => { + const commandId = item.command; + const id = 'navigator.tabbar.toolbar.' + commandId; + const command = this.commandRegistry.getCommand(commandId); + this.commandRegistry.registerCommand({ id, iconClass: command && command.iconClass }, { + execute: (w, ...args) => w instanceof FileNavigatorWidget + && this.commandRegistry.executeCommand(commandId, ...args), + isEnabled: (w, ...args) => w instanceof FileNavigatorWidget + && this.commandRegistry.isEnabled(commandId, ...args), + isVisible: (w, ...args) => w instanceof FileNavigatorWidget + && this.commandRegistry.isVisible(commandId, ...args), + isToggled: (w, ...args) => w instanceof FileNavigatorWidget + && this.commandRegistry.isToggled(commandId, ...args), + }); + item.command = id; + toolbarRegistry.registerItem(item); + }; + navigatorRegisterItem({ + id: WorkspaceCommands.NEW_FILE.id, + command: WorkspaceCommands.NEW_FILE.id, + tooltip: WorkspaceCommands.NEW_FILE.label, + group: NavigatorMoreToolbarGroups.NEW_OPEN, + }); + navigatorRegisterItem({ + id: WorkspaceCommands.NEW_FOLDER.id, + command: WorkspaceCommands.NEW_FOLDER.id, + tooltip: WorkspaceCommands.NEW_FOLDER.label, + group: NavigatorMoreToolbarGroups.NEW_OPEN, + }); + navigatorRegisterItem({ + id: WorkspaceCommands.ADD_FOLDER.id, + command: WorkspaceCommands.ADD_FOLDER.id, + tooltip: WorkspaceCommands.ADD_FOLDER.label, + group: NavigatorMoreToolbarGroups.WORKSPACE, + }); } /** diff --git a/packages/workspace/src/browser/workspace-commands.ts b/packages/workspace/src/browser/workspace-commands.ts index 6397b97807c62..7c642079285d3 100644 --- a/packages/workspace/src/browser/workspace-commands.ts +++ b/packages/workspace/src/browser/workspace-commands.ts @@ -447,15 +447,29 @@ export class WorkspaceRootUriAwareCommandHandler extends UriAwareCommandHandler< super(selectionService, handler); } + isVisible(): boolean { + return !!this.workspaceService.tryGetRoots().length; + } + + isEnabled(): boolean { + return !!this.workspaceService.tryGetRoots().length; + } + protected getUri(): URI | undefined { const uri = super.getUri(); - if (this.workspaceService.isMultiRootWorkspaceEnabled) { - return uri; - } + // If the URI is available, return it immediately. if (uri) { return uri; } - const root = this.workspaceService.tryGetRoots()[0]; + // If a multi-root workspace is currently opened with at least one root, + // return the URI of the first available root. + if (this.workspaceService.isMultiRootWorkspaceOpened && + !!this.workspaceService.tryGetRoots().length) { + const firstRoot = this.workspaceService.tryGetRoots()[0]; + return new URI(firstRoot.uri); + } + // Return the workspace root URI if available. + const root = this.workspaceService.workspace; return root && new URI(root.uri); }