Path: blob/main/src/vs/workbench/browser/parts/panel/panelActions.ts
3296 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.'));25export const closeIcon = registerIcon('panel-close', Codicon.close, localize('closeIcon', 'Icon to close a panel.'));26const panelIcon = registerIcon('panel-layout-icon', Codicon.layoutPanel, localize('togglePanelOffIcon', 'Icon to toggle the panel off when it is on.'));27const panelOffIcon = registerIcon('panel-layout-icon-off', Codicon.layoutPanelOff, localize('togglePanelOnIcon', 'Icon to toggle the panel on when it is off.'));2829export class TogglePanelAction extends Action2 {3031static readonly ID = 'workbench.action.togglePanel';32static readonly LABEL = localize2('togglePanelVisibility', "Toggle Panel Visibility");3334constructor() {35super({36id: TogglePanelAction.ID,37title: TogglePanelAction.LABEL,38toggled: {39condition: PanelVisibleContext,40title: localize('closePanel', 'Hide Panel'),41icon: closeIcon,42mnemonicTitle: localize({ key: 'miTogglePanelMnemonic', comment: ['&& denotes a mnemonic'] }, "&&Panel"),43},44icon: closeIcon,45f1: true,46category: Categories.View,47metadata: {48description: localize('openAndClosePanel', 'Open/Show and Close/Hide Panel'),49},50keybinding: { primary: KeyMod.CtrlCmd | KeyCode.KeyJ, weight: KeybindingWeight.WorkbenchContrib },51menu: [52{53id: MenuId.MenubarAppearanceMenu,54group: '2_workbench_layout',55order: 556}, {57id: MenuId.LayoutControlMenuSubmenu,58group: '0_workbench_layout',59order: 460}61]62});63}6465override async run(accessor: ServicesAccessor): Promise<void> {66const layoutService = accessor.get(IWorkbenchLayoutService);67layoutService.setPartHidden(layoutService.isVisible(Parts.PANEL_PART), Parts.PANEL_PART);68}69}7071registerAction2(TogglePanelAction);7273MenuRegistry.appendMenuItem(MenuId.PanelTitle, {74command: {75id: TogglePanelAction.ID,76title: localize('closePanel', 'Hide Panel'),77icon: closeIcon78},79group: 'navigation',80order: 281});8283registerAction2(class extends Action2 {84constructor() {85super({86id: 'workbench.action.closePanel',87title: localize2('closePanel', 'Hide Panel'),88category: Categories.View,89precondition: PanelVisibleContext,90f1: true,91});92}93run(accessor: ServicesAccessor) {94accessor.get(IWorkbenchLayoutService).setPartHidden(true, Parts.PANEL_PART);95}96});9798registerAction2(class extends Action2 {99100static readonly ID = 'workbench.action.focusPanel';101static readonly LABEL = localize('focusPanel', "Focus into Panel");102103constructor() {104super({105id: 'workbench.action.focusPanel',106title: localize2('focusPanel', "Focus into Panel"),107category: Categories.View,108f1: true,109});110}111112override async run(accessor: ServicesAccessor): Promise<void> {113const layoutService = accessor.get(IWorkbenchLayoutService);114const paneCompositeService = accessor.get(IPaneCompositePartService);115116// Show panel117if (!layoutService.isVisible(Parts.PANEL_PART)) {118layoutService.setPartHidden(false, Parts.PANEL_PART);119}120121// Focus into active panel122const panel = paneCompositeService.getActivePaneComposite(ViewContainerLocation.Panel);123panel?.focus();124}125});126127const PositionPanelActionId = {128LEFT: 'workbench.action.positionPanelLeft',129RIGHT: 'workbench.action.positionPanelRight',130BOTTOM: 'workbench.action.positionPanelBottom',131TOP: 'workbench.action.positionPanelTop'132};133134const AlignPanelActionId = {135LEFT: 'workbench.action.alignPanelLeft',136RIGHT: 'workbench.action.alignPanelRight',137CENTER: 'workbench.action.alignPanelCenter',138JUSTIFY: 'workbench.action.alignPanelJustify',139};140141interface PanelActionConfig<T> {142id: string;143when: ContextKeyExpression;144title: ICommandActionTitle;145shortLabel: string;146value: T;147}148149function createPanelActionConfig<T>(id: string, title: ICommandActionTitle, shortLabel: string, value: T, when: ContextKeyExpression): PanelActionConfig<T> {150return {151id,152title,153shortLabel,154value,155when,156};157}158159function createPositionPanelActionConfig(id: string, title: ICommandActionTitle, shortLabel: string, position: Position): PanelActionConfig<Position> {160return createPanelActionConfig<Position>(id, title, shortLabel, position, PanelPositionContext.notEqualsTo(positionToString(position)));161}162163function createAlignmentPanelActionConfig(id: string, title: ICommandActionTitle, shortLabel: string, alignment: PanelAlignment): PanelActionConfig<PanelAlignment> {164return createPanelActionConfig<PanelAlignment>(id, title, shortLabel, alignment, PanelAlignmentContext.notEqualsTo(alignment));165}166167const PositionPanelActionConfigs: PanelActionConfig<Position>[] = [168createPositionPanelActionConfig(PositionPanelActionId.TOP, localize2('positionPanelTop', "Move Panel To Top"), localize('positionPanelTopShort', "Top"), Position.TOP),169createPositionPanelActionConfig(PositionPanelActionId.LEFT, localize2('positionPanelLeft', "Move Panel Left"), localize('positionPanelLeftShort', "Left"), Position.LEFT),170createPositionPanelActionConfig(PositionPanelActionId.RIGHT, localize2('positionPanelRight', "Move Panel Right"), localize('positionPanelRightShort', "Right"), Position.RIGHT),171createPositionPanelActionConfig(PositionPanelActionId.BOTTOM, localize2('positionPanelBottom', "Move Panel To Bottom"), localize('positionPanelBottomShort', "Bottom"), Position.BOTTOM),172];173174175const AlignPanelActionConfigs: PanelActionConfig<PanelAlignment>[] = [176createAlignmentPanelActionConfig(AlignPanelActionId.LEFT, localize2('alignPanelLeft', "Set Panel Alignment to Left"), localize('alignPanelLeftShort', "Left"), 'left'),177createAlignmentPanelActionConfig(AlignPanelActionId.RIGHT, localize2('alignPanelRight', "Set Panel Alignment to Right"), localize('alignPanelRightShort', "Right"), 'right'),178createAlignmentPanelActionConfig(AlignPanelActionId.CENTER, localize2('alignPanelCenter', "Set Panel Alignment to Center"), localize('alignPanelCenterShort', "Center"), 'center'),179createAlignmentPanelActionConfig(AlignPanelActionId.JUSTIFY, localize2('alignPanelJustify', "Set Panel Alignment to Justify"), localize('alignPanelJustifyShort', "Justify"), 'justify'),180];181182MenuRegistry.appendMenuItem(MenuId.MenubarAppearanceMenu, {183submenu: MenuId.PanelPositionMenu,184title: localize('positionPanel', "Panel Position"),185group: '3_workbench_layout_move',186order: 4187});188189PositionPanelActionConfigs.forEach((positionPanelAction, index) => {190const { id, title, shortLabel, value, when } = positionPanelAction;191192registerAction2(class extends Action2 {193constructor() {194super({195id,196title,197category: Categories.View,198f1: true199});200}201run(accessor: ServicesAccessor): void {202const layoutService = accessor.get(IWorkbenchLayoutService);203layoutService.setPanelPosition(value === undefined ? Position.BOTTOM : value);204}205});206207MenuRegistry.appendMenuItem(MenuId.PanelPositionMenu, {208command: {209id,210title: shortLabel,211toggled: when.negate()212},213order: 5 + index214});215});216217MenuRegistry.appendMenuItem(MenuId.MenubarAppearanceMenu, {218submenu: MenuId.PanelAlignmentMenu,219title: localize('alignPanel', "Align Panel"),220group: '3_workbench_layout_move',221order: 5222});223224AlignPanelActionConfigs.forEach(alignPanelAction => {225const { id, title, shortLabel, value, when } = alignPanelAction;226registerAction2(class extends Action2 {227constructor() {228super({229id,230title,231category: Categories.View,232toggled: when.negate(),233f1: true234});235}236run(accessor: ServicesAccessor): void {237const layoutService = accessor.get(IWorkbenchLayoutService);238layoutService.setPanelAlignment(value === undefined ? 'center' : value);239}240});241242MenuRegistry.appendMenuItem(MenuId.PanelAlignmentMenu, {243command: {244id,245title: shortLabel,246toggled: when.negate()247},248order: 5249});250});251252registerAction2(class extends SwitchCompositeViewAction {253constructor() {254super({255id: 'workbench.action.previousPanelView',256title: localize2('previousPanelView', "Previous Panel View"),257category: Categories.View,258f1: true259}, ViewContainerLocation.Panel, -1);260}261});262263registerAction2(class extends SwitchCompositeViewAction {264constructor() {265super({266id: 'workbench.action.nextPanelView',267title: localize2('nextPanelView', "Next Panel View"),268category: Categories.View,269f1: true270}, ViewContainerLocation.Panel, 1);271}272});273274registerAction2(class extends Action2 {275constructor() {276super({277id: 'workbench.action.toggleMaximizedPanel',278title: localize2('toggleMaximizedPanel', 'Toggle Maximized Panel'),279tooltip: localize('maximizePanel', "Maximize Panel Size"),280category: Categories.View,281f1: true,282icon: maximizeIcon,283// the workbench grid currently prevents us from supporting panel maximization with non-center panel alignment284precondition: ContextKeyExpr.or(PanelAlignmentContext.isEqualTo('center'), ContextKeyExpr.and(PanelPositionContext.notEqualsTo('bottom'), PanelPositionContext.notEqualsTo('top'))),285toggled: { condition: PanelMaximizedContext, icon: maximizeIcon, tooltip: localize('minimizePanel', "Restore Panel Size") },286menu: [{287id: MenuId.PanelTitle,288group: 'navigation',289order: 1,290// the workbench grid currently prevents us from supporting panel maximization with non-center panel alignment291when: ContextKeyExpr.or(PanelAlignmentContext.isEqualTo('center'), ContextKeyExpr.and(PanelPositionContext.notEqualsTo('bottom'), PanelPositionContext.notEqualsTo('top')))292}]293});294}295run(accessor: ServicesAccessor) {296const layoutService = accessor.get(IWorkbenchLayoutService);297const notificationService = accessor.get(INotificationService);298if (layoutService.getPanelAlignment() !== 'center' && isHorizontal(layoutService.getPanelPosition())) {299notificationService.warn(localize('panelMaxNotSupported', "Maximizing the panel is only supported when it is center aligned."));300return;301}302303if (!layoutService.isVisible(Parts.PANEL_PART)) {304layoutService.setPartHidden(false, Parts.PANEL_PART);305// If the panel is not already maximized, maximize it306if (!layoutService.isPanelMaximized()) {307layoutService.toggleMaximizedPanel();308}309}310else {311layoutService.toggleMaximizedPanel();312}313}314});315316MenuRegistry.appendMenuItems([317{318id: MenuId.LayoutControlMenu,319item: {320group: '2_pane_toggles',321command: {322id: TogglePanelAction.ID,323title: localize('togglePanel', "Toggle Panel"),324icon: panelOffIcon,325toggled: { condition: PanelVisibleContext, icon: panelIcon }326},327when:328ContextKeyExpr.and(329IsAuxiliaryWindowContext.negate(),330ContextKeyExpr.or(331ContextKeyExpr.equals('config.workbench.layoutControl.type', 'toggles'),332ContextKeyExpr.equals('config.workbench.layoutControl.type', 'both')333)334),335order: 1336}337}338]);339340class MoveViewsBetweenPanelsAction extends Action2 {341constructor(private readonly source: ViewContainerLocation, private readonly destination: ViewContainerLocation, desc: Readonly<IAction2Options>) {342super(desc);343}344345run(accessor: ServicesAccessor, ...args: any[]): void {346const viewDescriptorService = accessor.get(IViewDescriptorService);347const layoutService = accessor.get(IWorkbenchLayoutService);348const viewsService = accessor.get(IViewsService);349350const srcContainers = viewDescriptorService.getViewContainersByLocation(this.source);351const destContainers = viewDescriptorService.getViewContainersByLocation(this.destination);352353if (srcContainers.length) {354const activeViewContainer = viewsService.getVisibleViewContainer(this.source);355356srcContainers.forEach(viewContainer => viewDescriptorService.moveViewContainerToLocation(viewContainer, this.destination, undefined, this.desc.id));357layoutService.setPartHidden(false, this.destination === ViewContainerLocation.Panel ? Parts.PANEL_PART : Parts.AUXILIARYBAR_PART);358359if (activeViewContainer && destContainers.length === 0) {360viewsService.openViewContainer(activeViewContainer.id, true);361}362}363}364}365366// --- Move Panel Views To Secondary Side Bar367368class MovePanelToSidePanelAction extends MoveViewsBetweenPanelsAction {369static readonly ID = 'workbench.action.movePanelToSidePanel';370constructor() {371super(ViewContainerLocation.Panel, ViewContainerLocation.AuxiliaryBar, {372id: MovePanelToSidePanelAction.ID,373title: localize2('movePanelToSecondarySideBar', "Move Panel Views To Secondary Side Bar"),374category: Categories.View,375f1: false376});377}378}379380export class MovePanelToSecondarySideBarAction extends MoveViewsBetweenPanelsAction {381static readonly ID = 'workbench.action.movePanelToSecondarySideBar';382constructor() {383super(ViewContainerLocation.Panel, ViewContainerLocation.AuxiliaryBar, {384id: MovePanelToSecondarySideBarAction.ID,385title: localize2('movePanelToSecondarySideBar', "Move Panel Views To Secondary Side Bar"),386category: Categories.View,387f1: true388});389}390}391392registerAction2(MovePanelToSidePanelAction);393registerAction2(MovePanelToSecondarySideBarAction);394395// --- Move Secondary Side Bar Views To Panel396397class MoveSidePanelToPanelAction extends MoveViewsBetweenPanelsAction {398static readonly ID = 'workbench.action.moveSidePanelToPanel';399400constructor() {401super(ViewContainerLocation.AuxiliaryBar, ViewContainerLocation.Panel, {402id: MoveSidePanelToPanelAction.ID,403title: localize2('moveSidePanelToPanel', "Move Secondary Side Bar Views To Panel"),404category: Categories.View,405f1: false406});407}408}409410export class MoveSecondarySideBarToPanelAction extends MoveViewsBetweenPanelsAction {411static readonly ID = 'workbench.action.moveSecondarySideBarToPanel';412413constructor() {414super(ViewContainerLocation.AuxiliaryBar, ViewContainerLocation.Panel, {415id: MoveSecondarySideBarToPanelAction.ID,416title: localize2('moveSidePanelToPanel', "Move Secondary Side Bar Views To Panel"),417category: Categories.View,418f1: true419});420}421}422registerAction2(MoveSidePanelToPanelAction);423registerAction2(MoveSecondarySideBarToPanelAction);424425426