Path: blob/main/src/vs/workbench/browser/parts/panel/panelActions.ts
5318 views
/*---------------------------------------------------------------------------------------------1* Copyright (c) Microsoft Corporation. All rights reserved.2* Licensed under the MIT License. See License.txt in the project root for license information.3*--------------------------------------------------------------------------------------------*/45import './media/panelpart.css';6import { localize, localize2 } from '../../../../nls.js';7import { KeyMod, KeyCode } from '../../../../base/common/keyCodes.js';8import { MenuId, MenuRegistry, registerAction2, Action2, IAction2Options } from '../../../../platform/actions/common/actions.js';9import { Categories } from '../../../../platform/action/common/actionCommonCategories.js';10import { isHorizontal, IWorkbenchLayoutService, PanelAlignment, Parts, Position, positionToString } from '../../../services/layout/browser/layoutService.js';11import { IsAuxiliaryWindowContext, PanelAlignmentContext, PanelMaximizedContext, PanelPositionContext, PanelVisibleContext } from '../../../common/contextkeys.js';12import { ContextKeyExpr, ContextKeyExpression } from '../../../../platform/contextkey/common/contextkey.js';13import { Codicon } from '../../../../base/common/codicons.js';14import { registerIcon } from '../../../../platform/theme/common/iconRegistry.js';15import { ServicesAccessor } from '../../../../editor/browser/editorExtensions.js';16import { ViewContainerLocation, IViewDescriptorService } from '../../../common/views.js';17import { IViewsService } from '../../../services/views/common/viewsService.js';18import { IPaneCompositePartService } from '../../../services/panecomposite/browser/panecomposite.js';19import { INotificationService } from '../../../../platform/notification/common/notification.js';20import { ICommandActionTitle } from '../../../../platform/action/common/action.js';21import { KeybindingWeight } from '../../../../platform/keybinding/common/keybindingsRegistry.js';22import { SwitchCompositeViewAction } from '../compositeBarActions.js';2324const maximizeIcon = registerIcon('panel-maximize', Codicon.screenFull, localize('maximizeIcon', 'Icon to maximize a panel.'));25const restoreIcon = registerIcon('panel-restore', Codicon.screenNormal, localize('restoreIcon', 'Icon to restore a panel.'));26const closeIcon = registerIcon('panel-close', Codicon.close, localize('closeIcon', 'Icon to close a panel.'));27const panelIcon = registerIcon('panel-layout-icon', Codicon.layoutPanel, localize('togglePanelOffIcon', 'Icon to toggle the panel off when it is on.'));28const panelOffIcon = registerIcon('panel-layout-icon-off', Codicon.layoutPanelOff, localize('togglePanelOnIcon', 'Icon to toggle the panel on when it is off.'));2930export class TogglePanelAction extends Action2 {3132static readonly ID = 'workbench.action.togglePanel';33static readonly LABEL = localize2('togglePanelVisibility', "Toggle Panel Visibility");3435constructor() {36super({37id: TogglePanelAction.ID,38title: TogglePanelAction.LABEL,39toggled: {40condition: PanelVisibleContext,41title: localize('closePanel', 'Hide Panel'),42icon: closeIcon,43mnemonicTitle: localize({ key: 'miTogglePanelMnemonic', comment: ['&& denotes a mnemonic'] }, "&&Panel"),44},45icon: closeIcon,46f1: true,47category: Categories.View,48metadata: {49description: localize('openAndClosePanel', 'Open/Show and Close/Hide Panel'),50},51keybinding: { primary: KeyMod.CtrlCmd | KeyCode.KeyJ, weight: KeybindingWeight.WorkbenchContrib },52menu: [53{54id: MenuId.MenubarAppearanceMenu,55group: '2_workbench_layout',56order: 557}, {58id: MenuId.LayoutControlMenuSubmenu,59group: '0_workbench_layout',60order: 461}62]63});64}6566override async run(accessor: ServicesAccessor): Promise<void> {67const layoutService = accessor.get(IWorkbenchLayoutService);68layoutService.setPartHidden(layoutService.isVisible(Parts.PANEL_PART), Parts.PANEL_PART);69}70}7172registerAction2(TogglePanelAction);7374MenuRegistry.appendMenuItem(MenuId.PanelTitle, {75command: {76id: TogglePanelAction.ID,77title: localize('closePanel', 'Hide Panel'),78icon: closeIcon79},80group: 'navigation',81order: 282});8384registerAction2(class extends Action2 {85constructor() {86super({87id: 'workbench.action.closePanel',88title: localize2('closePanel', 'Hide Panel'),89category: Categories.View,90precondition: PanelVisibleContext,91f1: true,92});93}94run(accessor: ServicesAccessor) {95accessor.get(IWorkbenchLayoutService).setPartHidden(true, Parts.PANEL_PART);96}97});9899registerAction2(class extends Action2 {100101static readonly ID = 'workbench.action.focusPanel';102static readonly LABEL = localize('focusPanel', "Focus into Panel");103104constructor() {105super({106id: 'workbench.action.focusPanel',107title: localize2('focusPanel', "Focus into Panel"),108category: Categories.View,109f1: true,110});111}112113override async run(accessor: ServicesAccessor): Promise<void> {114const layoutService = accessor.get(IWorkbenchLayoutService);115const paneCompositeService = accessor.get(IPaneCompositePartService);116117// Show panel118if (!layoutService.isVisible(Parts.PANEL_PART)) {119layoutService.setPartHidden(false, Parts.PANEL_PART);120}121122// Focus into active panel123const panel = paneCompositeService.getActivePaneComposite(ViewContainerLocation.Panel);124panel?.focus();125}126});127128const PositionPanelActionId = {129LEFT: 'workbench.action.positionPanelLeft',130RIGHT: 'workbench.action.positionPanelRight',131BOTTOM: 'workbench.action.positionPanelBottom',132TOP: 'workbench.action.positionPanelTop'133};134135const AlignPanelActionId = {136LEFT: 'workbench.action.alignPanelLeft',137RIGHT: 'workbench.action.alignPanelRight',138CENTER: 'workbench.action.alignPanelCenter',139JUSTIFY: 'workbench.action.alignPanelJustify',140};141142interface PanelActionConfig<T> {143id: string;144when: ContextKeyExpression;145title: ICommandActionTitle;146shortLabel: string;147value: T;148}149150function createPanelActionConfig<T>(id: string, title: ICommandActionTitle, shortLabel: string, value: T, when: ContextKeyExpression): PanelActionConfig<T> {151return {152id,153title,154shortLabel,155value,156when,157};158}159160function createPositionPanelActionConfig(id: string, title: ICommandActionTitle, shortLabel: string, position: Position): PanelActionConfig<Position> {161return createPanelActionConfig<Position>(id, title, shortLabel, position, PanelPositionContext.notEqualsTo(positionToString(position)));162}163164function createAlignmentPanelActionConfig(id: string, title: ICommandActionTitle, shortLabel: string, alignment: PanelAlignment): PanelActionConfig<PanelAlignment> {165return createPanelActionConfig<PanelAlignment>(id, title, shortLabel, alignment, PanelAlignmentContext.notEqualsTo(alignment));166}167168const PositionPanelActionConfigs: PanelActionConfig<Position>[] = [169createPositionPanelActionConfig(PositionPanelActionId.TOP, localize2('positionPanelTop', "Move Panel To Top"), localize('positionPanelTopShort', "Top"), Position.TOP),170createPositionPanelActionConfig(PositionPanelActionId.LEFT, localize2('positionPanelLeft', "Move Panel Left"), localize('positionPanelLeftShort', "Left"), Position.LEFT),171createPositionPanelActionConfig(PositionPanelActionId.RIGHT, localize2('positionPanelRight', "Move Panel Right"), localize('positionPanelRightShort', "Right"), Position.RIGHT),172createPositionPanelActionConfig(PositionPanelActionId.BOTTOM, localize2('positionPanelBottom', "Move Panel To Bottom"), localize('positionPanelBottomShort', "Bottom"), Position.BOTTOM),173];174175176const AlignPanelActionConfigs: PanelActionConfig<PanelAlignment>[] = [177createAlignmentPanelActionConfig(AlignPanelActionId.LEFT, localize2('alignPanelLeft', "Set Panel Alignment to Left"), localize('alignPanelLeftShort', "Left"), 'left'),178createAlignmentPanelActionConfig(AlignPanelActionId.RIGHT, localize2('alignPanelRight', "Set Panel Alignment to Right"), localize('alignPanelRightShort', "Right"), 'right'),179createAlignmentPanelActionConfig(AlignPanelActionId.CENTER, localize2('alignPanelCenter', "Set Panel Alignment to Center"), localize('alignPanelCenterShort', "Center"), 'center'),180createAlignmentPanelActionConfig(AlignPanelActionId.JUSTIFY, localize2('alignPanelJustify', "Set Panel Alignment to Justify"), localize('alignPanelJustifyShort', "Justify"), 'justify'),181];182183MenuRegistry.appendMenuItem(MenuId.MenubarAppearanceMenu, {184submenu: MenuId.PanelPositionMenu,185title: localize('positionPanel', "Panel Position"),186group: '3_workbench_layout_move',187order: 4188});189190PositionPanelActionConfigs.forEach((positionPanelAction, index) => {191const { id, title, shortLabel, value, when } = positionPanelAction;192193registerAction2(class extends Action2 {194constructor() {195super({196id,197title,198category: Categories.View,199f1: true200});201}202run(accessor: ServicesAccessor): void {203const layoutService = accessor.get(IWorkbenchLayoutService);204layoutService.setPanelPosition(value === undefined ? Position.BOTTOM : value);205}206});207208MenuRegistry.appendMenuItem(MenuId.PanelPositionMenu, {209command: {210id,211title: shortLabel,212toggled: when.negate()213},214order: 5 + index215});216});217218MenuRegistry.appendMenuItem(MenuId.MenubarAppearanceMenu, {219submenu: MenuId.PanelAlignmentMenu,220title: localize('alignPanel', "Align Panel"),221group: '3_workbench_layout_move',222order: 5223});224225AlignPanelActionConfigs.forEach(alignPanelAction => {226const { id, title, shortLabel, value, when } = alignPanelAction;227registerAction2(class extends Action2 {228constructor() {229super({230id,231title,232category: Categories.View,233toggled: when.negate(),234f1: true235});236}237run(accessor: ServicesAccessor): void {238const layoutService = accessor.get(IWorkbenchLayoutService);239layoutService.setPanelAlignment(value === undefined ? 'center' : value);240}241});242243MenuRegistry.appendMenuItem(MenuId.PanelAlignmentMenu, {244command: {245id,246title: shortLabel,247toggled: when.negate()248},249order: 5250});251});252253registerAction2(class extends SwitchCompositeViewAction {254constructor() {255super({256id: 'workbench.action.previousPanelView',257title: localize2('previousPanelView', "Previous Panel View"),258category: Categories.View,259f1: true260}, ViewContainerLocation.Panel, -1);261}262});263264registerAction2(class extends SwitchCompositeViewAction {265constructor() {266super({267id: 'workbench.action.nextPanelView',268title: localize2('nextPanelView', "Next Panel View"),269category: Categories.View,270f1: true271}, ViewContainerLocation.Panel, 1);272}273});274275const panelMaximizationSupportedWhen = ContextKeyExpr.or(PanelAlignmentContext.isEqualTo('center'), ContextKeyExpr.and(PanelPositionContext.notEqualsTo('bottom'), PanelPositionContext.notEqualsTo('top')));276const ToggleMaximizedPanelActionId = 'workbench.action.toggleMaximizedPanel';277278registerAction2(class extends Action2 {279constructor() {280super({281id: ToggleMaximizedPanelActionId,282title: localize2('toggleMaximizedPanel', 'Toggle Maximized Panel'),283tooltip: localize('maximizePanel', "Maximize Panel Size"),284category: Categories.View,285f1: true,286icon: maximizeIcon,287precondition: panelMaximizationSupportedWhen, // the workbench grid currently prevents us from supporting panel maximization with non-center panel alignment288});289}290run(accessor: ServicesAccessor) {291const layoutService = accessor.get(IWorkbenchLayoutService);292const notificationService = accessor.get(INotificationService);293if (layoutService.getPanelAlignment() !== 'center' && isHorizontal(layoutService.getPanelPosition())) {294notificationService.warn(localize('panelMaxNotSupported', "Maximizing the panel is only supported when it is center aligned."));295return;296}297298if (!layoutService.isVisible(Parts.PANEL_PART)) {299layoutService.setPartHidden(false, Parts.PANEL_PART);300// If the panel is not already maximized, maximize it301if (!layoutService.isPanelMaximized()) {302layoutService.toggleMaximizedPanel();303}304}305else {306layoutService.toggleMaximizedPanel();307}308}309});310311MenuRegistry.appendMenuItem(MenuId.PanelTitle, {312command: {313id: ToggleMaximizedPanelActionId,314title: localize('maximizePanel', "Maximize Panel Size"),315icon: maximizeIcon316},317group: 'navigation',318order: 1,319when: ContextKeyExpr.and(panelMaximizationSupportedWhen, PanelMaximizedContext.negate())320});321322MenuRegistry.appendMenuItem(MenuId.PanelTitle, {323command: {324id: ToggleMaximizedPanelActionId,325title: localize('minimizePanel', "Restore Panel Size"),326icon: restoreIcon327},328group: 'navigation',329order: 1,330when: ContextKeyExpr.and(panelMaximizationSupportedWhen, PanelMaximizedContext)331});332333MenuRegistry.appendMenuItems([334{335id: MenuId.LayoutControlMenu,336item: {337group: '2_pane_toggles',338command: {339id: TogglePanelAction.ID,340title: localize('togglePanel', "Toggle Panel"),341icon: panelOffIcon,342toggled: { condition: PanelVisibleContext, icon: panelIcon }343},344when:345ContextKeyExpr.and(346IsAuxiliaryWindowContext.negate(),347ContextKeyExpr.or(348ContextKeyExpr.equals('config.workbench.layoutControl.type', 'toggles'),349ContextKeyExpr.equals('config.workbench.layoutControl.type', 'both')350)351),352order: 1353}354}355]);356357class MoveViewsBetweenPanelsAction extends Action2 {358constructor(private readonly source: ViewContainerLocation, private readonly destination: ViewContainerLocation, desc: Readonly<IAction2Options>) {359super(desc);360}361362run(accessor: ServicesAccessor, ...args: unknown[]): void {363const viewDescriptorService = accessor.get(IViewDescriptorService);364const layoutService = accessor.get(IWorkbenchLayoutService);365const viewsService = accessor.get(IViewsService);366367const srcContainers = viewDescriptorService.getViewContainersByLocation(this.source);368const destContainers = viewDescriptorService.getViewContainersByLocation(this.destination);369370if (srcContainers.length) {371const activeViewContainer = viewsService.getVisibleViewContainer(this.source);372373srcContainers.forEach(viewContainer => viewDescriptorService.moveViewContainerToLocation(viewContainer, this.destination, undefined, this.desc.id));374layoutService.setPartHidden(false, this.destination === ViewContainerLocation.Panel ? Parts.PANEL_PART : Parts.AUXILIARYBAR_PART);375376if (activeViewContainer && destContainers.length === 0) {377viewsService.openViewContainer(activeViewContainer.id, true);378}379}380}381}382383// --- Move Panel Views To Secondary Side Bar384385class MovePanelToSidePanelAction extends MoveViewsBetweenPanelsAction {386static readonly ID = 'workbench.action.movePanelToSidePanel';387constructor() {388super(ViewContainerLocation.Panel, ViewContainerLocation.AuxiliaryBar, {389id: MovePanelToSidePanelAction.ID,390title: localize2('movePanelToSecondarySideBar', "Move Panel Views To Secondary Side Bar"),391category: Categories.View,392f1: false393});394}395}396397export class MovePanelToSecondarySideBarAction extends MoveViewsBetweenPanelsAction {398static readonly ID = 'workbench.action.movePanelToSecondarySideBar';399constructor() {400super(ViewContainerLocation.Panel, ViewContainerLocation.AuxiliaryBar, {401id: MovePanelToSecondarySideBarAction.ID,402title: localize2('movePanelToSecondarySideBar', "Move Panel Views To Secondary Side Bar"),403category: Categories.View,404f1: true405});406}407}408409registerAction2(MovePanelToSidePanelAction);410registerAction2(MovePanelToSecondarySideBarAction);411412// --- Move Secondary Side Bar Views To Panel413414class MoveSidePanelToPanelAction extends MoveViewsBetweenPanelsAction {415static readonly ID = 'workbench.action.moveSidePanelToPanel';416417constructor() {418super(ViewContainerLocation.AuxiliaryBar, ViewContainerLocation.Panel, {419id: MoveSidePanelToPanelAction.ID,420title: localize2('moveSidePanelToPanel', "Move Secondary Side Bar Views To Panel"),421category: Categories.View,422f1: false423});424}425}426427export class MoveSecondarySideBarToPanelAction extends MoveViewsBetweenPanelsAction {428static readonly ID = 'workbench.action.moveSecondarySideBarToPanel';429430constructor() {431super(ViewContainerLocation.AuxiliaryBar, ViewContainerLocation.Panel, {432id: MoveSecondarySideBarToPanelAction.ID,433title: localize2('moveSidePanelToPanel', "Move Secondary Side Bar Views To Panel"),434category: Categories.View,435f1: true436});437}438}439registerAction2(MoveSidePanelToPanelAction);440registerAction2(MoveSecondarySideBarToPanelAction);441442443