Path: blob/main/src/vs/workbench/browser/parts/paneCompositePart.ts
5263 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/paneCompositePart.css';6import { Event } from '../../../base/common/event.js';7import { IInstantiationService } from '../../../platform/instantiation/common/instantiation.js';8import { IProgressIndicator } from '../../../platform/progress/common/progress.js';9import { Extensions, PaneComposite, PaneCompositeDescriptor, PaneCompositeRegistry } from '../panecomposite.js';10import { IPaneComposite } from '../../common/panecomposite.js';11import { IViewDescriptorService, ViewContainerLocation } from '../../common/views.js';12import { DisposableStore, MutableDisposable } from '../../../base/common/lifecycle.js';13import { IView } from '../../../base/browser/ui/grid/grid.js';14import { IWorkbenchLayoutService, Parts } from '../../services/layout/browser/layoutService.js';15import { CompositePart, ICompositePartOptions, ICompositeTitleLabel } from './compositePart.js';16import { IPaneCompositeBarOptions, PaneCompositeBar } from './paneCompositeBar.js';17import { Dimension, EventHelper, trackFocus, $, addDisposableListener, EventType, prepend, getWindow } from '../../../base/browser/dom.js';18import { Registry } from '../../../platform/registry/common/platform.js';19import { INotificationService } from '../../../platform/notification/common/notification.js';20import { IStorageService } from '../../../platform/storage/common/storage.js';21import { IContextMenuService } from '../../../platform/contextview/browser/contextView.js';22import { IKeybindingService } from '../../../platform/keybinding/common/keybinding.js';23import { IThemeService } from '../../../platform/theme/common/themeService.js';24import { IContextKey, IContextKeyService } from '../../../platform/contextkey/common/contextkey.js';25import { IExtensionService } from '../../services/extensions/common/extensions.js';26import { IComposite } from '../../common/composite.js';27import { localize } from '../../../nls.js';28import { CompositeDragAndDropObserver, toggleDropEffect } from '../dnd.js';29import { EDITOR_DRAG_AND_DROP_BACKGROUND } from '../../common/theme.js';30import { IMenuService, MenuId } from '../../../platform/actions/common/actions.js';31import { ActionsOrientation } from '../../../base/browser/ui/actionbar/actionbar.js';32import { Gesture, EventType as GestureEventType } from '../../../base/browser/touch.js';33import { StandardMouseEvent } from '../../../base/browser/mouseEvent.js';34import { IAction, SubmenuAction } from '../../../base/common/actions.js';35import { Composite } from '../composite.js';36import { ViewsSubMenu } from './views/viewPaneContainer.js';37import { getActionBarActions } from '../../../platform/actions/browser/menuEntryActionViewItem.js';38import { IHoverService } from '../../../platform/hover/browser/hover.js';39import { HiddenItemStrategy, MenuWorkbenchToolBar } from '../../../platform/actions/browser/toolbar.js';40import { DeferredPromise } from '../../../base/common/async.js';4142export enum CompositeBarPosition {43TOP,44TITLE,45BOTTOM46}4748export interface IPaneCompositePart extends IView {4950readonly partId: Parts.PANEL_PART | Parts.AUXILIARYBAR_PART | Parts.SIDEBAR_PART;5152readonly onDidPaneCompositeOpen: Event<IPaneComposite>;53readonly onDidPaneCompositeClose: Event<IPaneComposite>;5455/**56* Opens a viewlet with the given identifier and pass keyboard focus to it if specified.57*/58openPaneComposite(id: string | undefined, focus?: boolean): Promise<IPaneComposite | undefined>;5960/**61* Returns the current active viewlet if any.62*/63getActivePaneComposite(): IPaneComposite | undefined;6465/**66* Returns the viewlet by id.67*/68getPaneComposite(id: string): PaneCompositeDescriptor | undefined;6970/**71* Returns all enabled viewlets72*/73getPaneComposites(): PaneCompositeDescriptor[];7475/**76* Returns the progress indicator for the side bar.77*/78getProgressIndicator(id: string): IProgressIndicator | undefined;7980/**81* Hide the active viewlet.82*/83hideActivePaneComposite(): void;8485/**86* Return the last active viewlet id.87*/88getLastActivePaneCompositeId(): string;8990/**91* Returns id of pinned view containers following the visual order.92*/93getPinnedPaneCompositeIds(): string[];9495/**96* Returns id of visible view containers following the visual order.97*/98getVisiblePaneCompositeIds(): string[];99100/**101* Returns id of all view containers following the visual order.102*/103getPaneCompositeIds(): string[];104}105106export abstract class AbstractPaneCompositePart extends CompositePart<PaneComposite> implements IPaneCompositePart {107108private static readonly MIN_COMPOSITE_BAR_WIDTH = 50;109110get snap(): boolean {111// Always allow snapping closed112// Only allow dragging open if the panel contains view containers113return this.layoutService.isVisible(this.partId) || !!this.paneCompositeBar.value?.getVisiblePaneCompositeIds().length;114}115116get onDidPaneCompositeOpen(): Event<IPaneComposite> { return Event.map(this.onDidCompositeOpen.event, compositeEvent => <IPaneComposite>compositeEvent.composite); }117readonly onDidPaneCompositeClose = this.onDidCompositeClose.event as Event<IPaneComposite>;118119private readonly location: ViewContainerLocation;120private titleContainer: HTMLElement | undefined;121private headerFooterCompositeBarContainer: HTMLElement | undefined;122protected readonly headerFooterCompositeBarDispoables = this._register(new DisposableStore());123private paneCompositeBarContainer: HTMLElement | undefined;124private readonly paneCompositeBar = this._register(new MutableDisposable<PaneCompositeBar>());125private compositeBarPosition: CompositeBarPosition | undefined = undefined;126private emptyPaneMessageElement: HTMLElement | undefined;127128private readonly globalActionsMenuId: MenuId;129private globalToolBar: MenuWorkbenchToolBar | undefined;130131private blockOpening: DeferredPromise<PaneComposite | undefined> | undefined = undefined;132protected contentDimension: Dimension | undefined;133134constructor(135readonly partId: Parts.PANEL_PART | Parts.AUXILIARYBAR_PART | Parts.SIDEBAR_PART,136partOptions: ICompositePartOptions,137activePaneCompositeSettingsKey: string,138private readonly activePaneContextKey: IContextKey<string>,139private paneFocusContextKey: IContextKey<boolean>,140nameForTelemetry: string,141compositeCSSClass: string,142titleForegroundColor: string | undefined,143titleBorderColor: string | undefined,144@INotificationService notificationService: INotificationService,145@IStorageService storageService: IStorageService,146@IContextMenuService contextMenuService: IContextMenuService,147@IWorkbenchLayoutService layoutService: IWorkbenchLayoutService,148@IKeybindingService keybindingService: IKeybindingService,149@IHoverService hoverService: IHoverService,150@IInstantiationService instantiationService: IInstantiationService,151@IThemeService themeService: IThemeService,152@IViewDescriptorService private readonly viewDescriptorService: IViewDescriptorService,153@IContextKeyService protected readonly contextKeyService: IContextKeyService,154@IExtensionService private readonly extensionService: IExtensionService,155@IMenuService protected readonly menuService: IMenuService,156) {157let location = ViewContainerLocation.Sidebar;158let registryId = Extensions.Viewlets;159let globalActionsMenuId = MenuId.SidebarTitle;160if (partId === Parts.PANEL_PART) {161location = ViewContainerLocation.Panel;162registryId = Extensions.Panels;163globalActionsMenuId = MenuId.PanelTitle;164} else if (partId === Parts.AUXILIARYBAR_PART) {165location = ViewContainerLocation.AuxiliaryBar;166registryId = Extensions.Auxiliary;167globalActionsMenuId = MenuId.AuxiliaryBarTitle;168}169super(170notificationService,171storageService,172contextMenuService,173layoutService,174keybindingService,175hoverService,176instantiationService,177themeService,178Registry.as<PaneCompositeRegistry>(registryId),179activePaneCompositeSettingsKey,180viewDescriptorService.getDefaultViewContainer(location)?.id || '',181nameForTelemetry,182compositeCSSClass,183titleForegroundColor,184titleBorderColor,185partId,186partOptions187);188189this.location = location;190this.globalActionsMenuId = globalActionsMenuId;191this.registerListeners();192}193194private registerListeners(): void {195this._register(this.onDidPaneCompositeOpen(composite => this.onDidOpen(composite)));196this._register(this.onDidPaneCompositeClose(this.onDidClose, this));197198this._register(this.registry.onDidDeregister((viewletDescriptor: PaneCompositeDescriptor) => {199200const activeContainers = this.viewDescriptorService.getViewContainersByLocation(this.location)201.filter(container => this.viewDescriptorService.getViewContainerModel(container).activeViewDescriptors.length > 0);202203if (activeContainers.length) {204if (this.getActiveComposite()?.getId() === viewletDescriptor.id) {205const defaultViewletId = this.viewDescriptorService.getDefaultViewContainer(this.location)?.id;206const containerToOpen = activeContainers.filter(c => c.id === defaultViewletId)[0] || activeContainers[0];207this.doOpenPaneComposite(containerToOpen.id);208}209} else {210this.layoutService.setPartHidden(true, this.partId);211}212213this.removeComposite(viewletDescriptor.id);214}));215216this._register(this.extensionService.onDidRegisterExtensions(() => {217this.layoutCompositeBar();218}));219}220221private onDidOpen(composite: IComposite): void {222this.activePaneContextKey.set(composite.getId());223}224225private onDidClose(composite: IComposite): void {226const id = composite.getId();227if (this.activePaneContextKey.get() === id) {228this.activePaneContextKey.reset();229}230}231232protected override showComposite(composite: Composite): void {233super.showComposite(composite);234this.layoutCompositeBar();235this.layoutEmptyMessage();236}237238protected override hideActiveComposite(): Composite | undefined {239const composite = super.hideActiveComposite();240this.layoutCompositeBar();241this.layoutEmptyMessage();242return composite;243}244245override create(parent: HTMLElement): void {246this.element = parent;247this.element.classList.add('pane-composite-part');248249super.create(parent);250251if (this.contentArea) {252this.createEmptyPaneMessage(this.contentArea);253}254255this.updateCompositeBar();256257const focusTracker = this._register(trackFocus(parent));258this._register(focusTracker.onDidFocus(() => this.paneFocusContextKey.set(true)));259this._register(focusTracker.onDidBlur(() => this.paneFocusContextKey.set(false)));260}261262private createEmptyPaneMessage(parent: HTMLElement): void {263this.emptyPaneMessageElement = $('.empty-pane-message-area');264265const messageElement = $('.empty-pane-message');266messageElement.textContent = localize('pane.emptyMessage', "Drag a view here to display.");267268this.emptyPaneMessageElement.appendChild(messageElement);269parent.appendChild(this.emptyPaneMessageElement);270271const setDropBackgroundFeedback = (visible: boolean) => {272const updateActivityBarBackground = !this.getActiveComposite() || !visible;273const backgroundColor = visible ? this.theme.getColor(EDITOR_DRAG_AND_DROP_BACKGROUND)?.toString() || '' : '';274275if (this.titleContainer && updateActivityBarBackground) {276this.titleContainer.style.backgroundColor = backgroundColor;277}278if (this.headerFooterCompositeBarContainer && updateActivityBarBackground) {279this.headerFooterCompositeBarContainer.style.backgroundColor = backgroundColor;280}281282this.emptyPaneMessageElement!.style.backgroundColor = backgroundColor;283};284285this._register(CompositeDragAndDropObserver.INSTANCE.registerTarget(this.element, {286onDragOver: (e) => {287EventHelper.stop(e.eventData, true);288if (this.paneCompositeBar.value) {289const validDropTarget = this.paneCompositeBar.value.dndHandler.onDragEnter(e.dragAndDropData, undefined, e.eventData);290toggleDropEffect(e.eventData.dataTransfer, 'move', validDropTarget);291}292},293onDragEnter: (e) => {294EventHelper.stop(e.eventData, true);295if (this.paneCompositeBar.value) {296const validDropTarget = this.paneCompositeBar.value.dndHandler.onDragEnter(e.dragAndDropData, undefined, e.eventData);297setDropBackgroundFeedback(validDropTarget);298}299},300onDragLeave: (e) => {301EventHelper.stop(e.eventData, true);302setDropBackgroundFeedback(false);303},304onDragEnd: (e) => {305EventHelper.stop(e.eventData, true);306setDropBackgroundFeedback(false);307},308onDrop: (e) => {309EventHelper.stop(e.eventData, true);310setDropBackgroundFeedback(false);311if (this.paneCompositeBar.value) {312this.paneCompositeBar.value.dndHandler.drop(e.dragAndDropData, undefined, e.eventData);313} else {314// Allow opening views/composites if the composite bar is hidden315const dragData = e.dragAndDropData.getData();316317if (dragData.type === 'composite') {318const currentContainer = this.viewDescriptorService.getViewContainerById(dragData.id)!;319this.viewDescriptorService.moveViewContainerToLocation(currentContainer, this.location, undefined, 'dnd');320this.openPaneComposite(currentContainer.id, true);321}322323else if (dragData.type === 'view') {324const viewToMove = this.viewDescriptorService.getViewDescriptorById(dragData.id)!;325if (viewToMove.canMoveView) {326this.viewDescriptorService.moveViewToLocation(viewToMove, this.location, 'dnd');327328const newContainer = this.viewDescriptorService.getViewContainerByViewId(viewToMove.id)!;329330this.openPaneComposite(newContainer.id, true).then(composite => {331composite?.openView(viewToMove.id, true);332});333}334}335}336},337}));338}339340protected override createTitleArea(parent: HTMLElement): HTMLElement {341const titleArea = super.createTitleArea(parent);342343this._register(addDisposableListener(titleArea, EventType.CONTEXT_MENU, e => {344this.onTitleAreaContextMenu(new StandardMouseEvent(getWindow(titleArea), e));345}));346this._register(Gesture.addTarget(titleArea));347this._register(addDisposableListener(titleArea, GestureEventType.Contextmenu, e => {348this.onTitleAreaContextMenu(new StandardMouseEvent(getWindow(titleArea), e));349}));350351const globalTitleActionsContainer = titleArea.appendChild($('.global-actions'));352353// Global Actions Toolbar354this.globalToolBar = this._register(this.instantiationService.createInstance(MenuWorkbenchToolBar,355globalTitleActionsContainer,356this.globalActionsMenuId,357{358actionViewItemProvider: (action, options) => this.actionViewItemProvider(action, options),359orientation: ActionsOrientation.HORIZONTAL,360getKeyBinding: action => this.keybindingService.lookupKeybinding(action.id),361anchorAlignmentProvider: () => this.getTitleAreaDropDownAnchorAlignment(),362toggleMenuTitle: localize('moreActions', "More Actions..."),363hoverDelegate: this.toolbarHoverDelegate,364hiddenItemStrategy: HiddenItemStrategy.NoHide,365highlightToggledItems: true,366telemetrySource: this.nameForTelemetry367}368));369370return titleArea;371}372373protected override createTitleLabel(parent: HTMLElement): ICompositeTitleLabel {374this.titleContainer = parent;375376const titleLabel = super.createTitleLabel(parent);377this.titleLabelElement!.draggable = true;378const draggedItemProvider = (): { type: 'view' | 'composite'; id: string } => {379const activeViewlet = this.getActivePaneComposite()!;380return { type: 'composite', id: activeViewlet.getId() };381};382this._register(CompositeDragAndDropObserver.INSTANCE.registerDraggable(this.titleLabelElement!, draggedItemProvider, {}));383384return titleLabel;385}386387protected updateCompositeBar(updateCompositeBarOption: boolean = false): void {388const wasCompositeBarVisible = this.compositeBarPosition !== undefined;389const isCompositeBarVisible = this.shouldShowCompositeBar();390const previousPosition = this.compositeBarPosition;391const newPosition = isCompositeBarVisible ? this.getCompositeBarPosition() : undefined;392393// Only update if the visibility or position has changed or if the composite bar options should be updated394if (!updateCompositeBarOption && previousPosition === newPosition) {395return;396}397398// Remove old composite bar399if (wasCompositeBarVisible) {400const previousCompositeBarContainer = previousPosition === CompositeBarPosition.TITLE ? this.titleContainer : this.headerFooterCompositeBarContainer;401if (!this.paneCompositeBarContainer || !this.paneCompositeBar.value || !previousCompositeBarContainer) {402throw new Error('Composite bar containers should exist when removing the previous composite bar');403}404405this.paneCompositeBarContainer.remove();406this.paneCompositeBarContainer = undefined;407this.paneCompositeBar.value = undefined;408409previousCompositeBarContainer.classList.remove('has-composite-bar');410411if (previousPosition === CompositeBarPosition.TOP) {412this.removeFooterHeaderArea(true);413} else if (previousPosition === CompositeBarPosition.BOTTOM) {414this.removeFooterHeaderArea(false);415}416}417418// Create new composite bar419let newCompositeBarContainer;420switch (newPosition) {421case CompositeBarPosition.TOP: newCompositeBarContainer = this.createHeaderArea(); break;422case CompositeBarPosition.TITLE: newCompositeBarContainer = this.titleContainer; break;423case CompositeBarPosition.BOTTOM: newCompositeBarContainer = this.createFooterArea(); break;424}425if (isCompositeBarVisible) {426427if (this.paneCompositeBarContainer || this.paneCompositeBar.value || !newCompositeBarContainer) {428throw new Error('Invalid composite bar state when creating the new composite bar');429}430431newCompositeBarContainer.classList.add('has-composite-bar');432this.paneCompositeBarContainer = prepend(newCompositeBarContainer, $('.composite-bar-container'));433this.paneCompositeBar.value = this.createCompositeBar();434this.paneCompositeBar.value.create(this.paneCompositeBarContainer);435436if (newPosition === CompositeBarPosition.TOP) {437this.setHeaderArea(newCompositeBarContainer);438} else if (newPosition === CompositeBarPosition.BOTTOM) {439this.setFooterArea(newCompositeBarContainer);440}441}442443this.compositeBarPosition = newPosition;444445if (updateCompositeBarOption) {446this.layoutCompositeBar();447}448}449450protected override createHeaderArea(): HTMLElement {451const headerArea = super.createHeaderArea();452453return this.createHeaderFooterCompositeBarArea(headerArea);454}455456protected override createFooterArea(): HTMLElement {457const footerArea = super.createFooterArea();458459return this.createHeaderFooterCompositeBarArea(footerArea);460}461462protected createHeaderFooterCompositeBarArea(area: HTMLElement): HTMLElement {463if (this.headerFooterCompositeBarContainer) {464// A pane composite part has either a header or a footer, but not both465throw new Error('Header or Footer composite bar already exists');466}467this.headerFooterCompositeBarContainer = area;468469this.headerFooterCompositeBarDispoables.add(addDisposableListener(area, EventType.CONTEXT_MENU, e => {470this.onCompositeBarAreaContextMenu(new StandardMouseEvent(getWindow(area), e));471}));472this.headerFooterCompositeBarDispoables.add(Gesture.addTarget(area));473this.headerFooterCompositeBarDispoables.add(addDisposableListener(area, GestureEventType.Contextmenu, e => {474this.onCompositeBarAreaContextMenu(new StandardMouseEvent(getWindow(area), e));475}));476477return area;478}479480private removeFooterHeaderArea(header: boolean): void {481this.headerFooterCompositeBarContainer = undefined;482this.headerFooterCompositeBarDispoables.clear();483if (header) {484this.removeHeaderArea();485} else {486this.removeFooterArea();487}488}489490protected createCompositeBar(): PaneCompositeBar {491return this.instantiationService.createInstance(PaneCompositeBar, this.getCompositeBarOptions(), this.partId, this);492}493494protected override onTitleAreaUpdate(compositeId: string): void {495super.onTitleAreaUpdate(compositeId);496497// If title actions change, relayout the composite bar498this.layoutCompositeBar();499}500501async openPaneComposite(id?: string, focus?: boolean): Promise<PaneComposite | undefined> {502if (typeof id === 'string' && this.getPaneComposite(id)) {503return this.doOpenPaneComposite(id, focus);504}505506await this.extensionService.whenInstalledExtensionsRegistered();507508if (typeof id === 'string' && this.getPaneComposite(id)) {509return this.doOpenPaneComposite(id, focus);510}511512return undefined;513}514515private async doOpenPaneComposite(id: string, focus?: boolean): Promise<PaneComposite | undefined> {516if (this.blockOpening) {517// Workaround against a potential race condition when calling518// `setPartHidden` we may end up in `openPaneComposite` again.519// But we still want to return the result of the original call,520// so we return the promise of the original call.521return this.blockOpening.p;522}523524let blockOpening: DeferredPromise<PaneComposite | undefined> | undefined;525if (!this.layoutService.isVisible(this.partId)) {526try {527blockOpening = this.blockOpening = new DeferredPromise<PaneComposite | undefined>();528this.layoutService.setPartHidden(false, this.partId);529} finally {530this.blockOpening = undefined;531}532}533534try {535const result = this.openComposite(id, focus) as PaneComposite | undefined;536blockOpening?.complete(result);537538return result;539} catch (error) {540blockOpening?.error(error);541throw error;542}543}544545getPaneComposite(id: string): PaneCompositeDescriptor | undefined {546return (this.registry as PaneCompositeRegistry).getPaneComposite(id);547}548549getPaneComposites(): PaneCompositeDescriptor[] {550return (this.registry as PaneCompositeRegistry).getPaneComposites()551.sort((v1, v2) => {552if (typeof v1.order !== 'number') {553return 1;554}555556if (typeof v2.order !== 'number') {557return -1;558}559560return v1.order - v2.order;561});562}563564getPinnedPaneCompositeIds(): string[] {565return this.paneCompositeBar.value?.getPinnedPaneCompositeIds() ?? [];566}567568getVisiblePaneCompositeIds(): string[] {569return this.paneCompositeBar.value?.getVisiblePaneCompositeIds() ?? [];570}571572getPaneCompositeIds(): string[] {573return this.paneCompositeBar.value?.getPaneCompositeIds() ?? [];574}575576getActivePaneComposite(): IPaneComposite | undefined {577return <IPaneComposite>this.getActiveComposite();578}579580getLastActivePaneCompositeId(): string {581return this.getLastActiveCompositeId();582}583584hideActivePaneComposite(): void {585if (this.layoutService.isVisible(this.partId)) {586this.layoutService.setPartHidden(true, this.partId);587}588589this.hideActiveComposite();590}591592protected focusCompositeBar(): void {593this.paneCompositeBar.value?.focus();594}595596override layout(width: number, height: number, top: number, left: number): void {597if (!this.layoutService.isVisible(this.partId)) {598return;599}600601this.contentDimension = new Dimension(width, height);602603// Layout contents604super.layout(this.contentDimension.width, this.contentDimension.height, top, left);605606// Layout composite bar607this.layoutCompositeBar();608609// Add empty pane message610this.layoutEmptyMessage();611}612613private layoutCompositeBar(): void {614if (this.contentDimension && this.dimension && this.paneCompositeBar.value) {615const padding = this.compositeBarPosition === CompositeBarPosition.TITLE ? 16 : 8;616const borderWidth = this.partId === Parts.PANEL_PART ? 0 : 1;617let availableWidth = this.contentDimension.width - padding - borderWidth;618availableWidth = Math.max(AbstractPaneCompositePart.MIN_COMPOSITE_BAR_WIDTH, availableWidth - this.getToolbarWidth());619this.paneCompositeBar.value.layout(availableWidth, this.dimension.height);620}621}622623private layoutEmptyMessage(): void {624const visible = !this.getActiveComposite();625this.element.classList.toggle('empty', visible);626if (visible) {627this.titleLabel?.updateTitle('', '');628}629}630631protected getToolbarWidth(): number {632if (!this.toolBar || this.compositeBarPosition !== CompositeBarPosition.TITLE) {633return 0;634}635636const activePane = this.getActivePaneComposite();637if (!activePane) {638return 0;639}640641// Each toolbar item has 4px margin642const toolBarWidth = this.toolBar.getItemsWidth() + this.toolBar.getItemsLength() * 4;643const globalToolBarWidth = this.globalToolBar ? this.globalToolBar.getItemsWidth() + this.globalToolBar.getItemsLength() * 4 : 0;644return toolBarWidth + globalToolBarWidth + 8; // 8px padding left645}646647private onTitleAreaContextMenu(event: StandardMouseEvent): void {648if (this.shouldShowCompositeBar() && this.getCompositeBarPosition() === CompositeBarPosition.TITLE) {649return this.onCompositeBarContextMenu(event);650} else {651const activePaneComposite = this.getActivePaneComposite() as PaneComposite;652const activePaneCompositeActions = activePaneComposite ? activePaneComposite.getContextMenuActions() : [];653if (activePaneCompositeActions.length) {654this.contextMenuService.showContextMenu({655getAnchor: () => event,656getActions: () => activePaneCompositeActions,657getActionViewItem: (action, options) => this.actionViewItemProvider(action, options),658actionRunner: activePaneComposite.getActionRunner(),659skipTelemetry: true660});661}662}663}664665private onCompositeBarAreaContextMenu(event: StandardMouseEvent): void {666return this.onCompositeBarContextMenu(event);667}668669private onCompositeBarContextMenu(event: StandardMouseEvent): void {670if (this.paneCompositeBar.value) {671const actions: IAction[] = [...this.paneCompositeBar.value.getContextMenuActions()];672if (actions.length) {673this.contextMenuService.showContextMenu({674getAnchor: () => event,675getActions: () => actions,676skipTelemetry: true677});678}679}680}681682protected getViewsSubmenuAction(): SubmenuAction | undefined {683const viewPaneContainer = (this.getActivePaneComposite() as PaneComposite)?.getViewPaneContainer();684if (viewPaneContainer) {685const disposables = new DisposableStore();686const scopedContextKeyService = disposables.add(this.contextKeyService.createScoped(this.element));687scopedContextKeyService.createKey('viewContainer', viewPaneContainer.viewContainer.id);688const menu = this.menuService.getMenuActions(ViewsSubMenu, scopedContextKeyService, { shouldForwardArgs: true, renderShortTitle: true });689const viewsActions = getActionBarActions(menu, () => true).primary;690disposables.dispose();691return viewsActions.length > 1 && viewsActions.some(a => a.enabled) ? new SubmenuAction('views', localize('views', "Views"), viewsActions) : undefined;692}693return undefined;694}695696protected abstract shouldShowCompositeBar(): boolean;697protected abstract getCompositeBarOptions(): IPaneCompositeBarOptions;698protected abstract getCompositeBarPosition(): CompositeBarPosition;699}700701702