Path: blob/main/src/vs/workbench/browser/parts/paneCompositePart.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/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, 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 { IPartOptions } from '../part.js';31import { IMenuService, MenuId } from '../../../platform/actions/common/actions.js';32import { ActionsOrientation } from '../../../base/browser/ui/actionbar/actionbar.js';33import { Gesture, EventType as GestureEventType } from '../../../base/browser/touch.js';34import { StandardMouseEvent } from '../../../base/browser/mouseEvent.js';35import { IAction, SubmenuAction } from '../../../base/common/actions.js';36import { Composite } from '../composite.js';37import { ViewsSubMenu } from './views/viewPaneContainer.js';38import { getActionBarActions } from '../../../platform/actions/browser/menuEntryActionViewItem.js';39import { IHoverService } from '../../../platform/hover/browser/hover.js';40import { HiddenItemStrategy, MenuWorkbenchToolBar } from '../../../platform/actions/browser/toolbar.js';41import { DeferredPromise } from '../../../base/common/async.js';4243export enum CompositeBarPosition {44TOP,45TITLE,46BOTTOM47}4849export interface IPaneCompositePart extends IView {5051readonly partId: Parts.PANEL_PART | Parts.AUXILIARYBAR_PART | Parts.SIDEBAR_PART;5253readonly onDidPaneCompositeOpen: Event<IPaneComposite>;54readonly onDidPaneCompositeClose: Event<IPaneComposite>;5556/**57* Opens a viewlet with the given identifier and pass keyboard focus to it if specified.58*/59openPaneComposite(id: string | undefined, focus?: boolean): Promise<IPaneComposite | undefined>;6061/**62* Returns the current active viewlet if any.63*/64getActivePaneComposite(): IPaneComposite | undefined;6566/**67* Returns the viewlet by id.68*/69getPaneComposite(id: string): PaneCompositeDescriptor | undefined;7071/**72* Returns all enabled viewlets73*/74getPaneComposites(): PaneCompositeDescriptor[];7576/**77* Returns the progress indicator for the side bar.78*/79getProgressIndicator(id: string): IProgressIndicator | undefined;8081/**82* Hide the active viewlet.83*/84hideActivePaneComposite(): void;8586/**87* Return the last active viewlet id.88*/89getLastActivePaneCompositeId(): string;9091/**92* Returns id of pinned view containers following the visual order.93*/94getPinnedPaneCompositeIds(): string[];9596/**97* Returns id of visible view containers following the visual order.98*/99getVisiblePaneCompositeIds(): string[];100101/**102* Returns id of all view containers following the visual order.103*/104getPaneCompositeIds(): string[];105}106107export abstract class AbstractPaneCompositePart extends CompositePart<PaneComposite> implements IPaneCompositePart {108109private static readonly MIN_COMPOSITE_BAR_WIDTH = 50;110111get snap(): boolean {112// Always allow snapping closed113// Only allow dragging open if the panel contains view containers114return this.layoutService.isVisible(this.partId) || !!this.paneCompositeBar.value?.getVisiblePaneCompositeIds().length;115}116117get onDidPaneCompositeOpen(): Event<IPaneComposite> { return Event.map(this.onDidCompositeOpen.event, compositeEvent => <IPaneComposite>compositeEvent.composite); }118readonly onDidPaneCompositeClose = this.onDidCompositeClose.event as Event<IPaneComposite>;119120private readonly location: ViewContainerLocation;121private titleContainer: HTMLElement | undefined;122private headerFooterCompositeBarContainer: HTMLElement | undefined;123protected readonly headerFooterCompositeBarDispoables = this._register(new DisposableStore());124private paneCompositeBarContainer: HTMLElement | undefined;125private readonly paneCompositeBar = this._register(new MutableDisposable<PaneCompositeBar>());126private compositeBarPosition: CompositeBarPosition | undefined = undefined;127private emptyPaneMessageElement: HTMLElement | undefined;128129private readonly globalActionsMenuId: MenuId;130private globalToolBar: MenuWorkbenchToolBar | undefined;131132private blockOpening: DeferredPromise<PaneComposite | undefined> | undefined = undefined;133protected contentDimension: Dimension | undefined;134135constructor(136readonly partId: Parts.PANEL_PART | Parts.AUXILIARYBAR_PART | Parts.SIDEBAR_PART,137partOptions: IPartOptions,138activePaneCompositeSettingsKey: string,139private readonly activePaneContextKey: IContextKey<string>,140private paneFocusContextKey: IContextKey<boolean>,141nameForTelemetry: string,142compositeCSSClass: string,143titleForegroundColor: string | undefined,144titleBorderColor: string | undefined,145@INotificationService notificationService: INotificationService,146@IStorageService storageService: IStorageService,147@IContextMenuService contextMenuService: IContextMenuService,148@IWorkbenchLayoutService layoutService: IWorkbenchLayoutService,149@IKeybindingService keybindingService: IKeybindingService,150@IHoverService hoverService: IHoverService,151@IInstantiationService instantiationService: IInstantiationService,152@IThemeService themeService: IThemeService,153@IViewDescriptorService private readonly viewDescriptorService: IViewDescriptorService,154@IContextKeyService protected readonly contextKeyService: IContextKeyService,155@IExtensionService private readonly extensionService: IExtensionService,156@IMenuService protected readonly menuService: IMenuService,157) {158let location = ViewContainerLocation.Sidebar;159let registryId = Extensions.Viewlets;160let globalActionsMenuId = MenuId.SidebarTitle;161if (partId === Parts.PANEL_PART) {162location = ViewContainerLocation.Panel;163registryId = Extensions.Panels;164globalActionsMenuId = MenuId.PanelTitle;165} else if (partId === Parts.AUXILIARYBAR_PART) {166location = ViewContainerLocation.AuxiliaryBar;167registryId = Extensions.Auxiliary;168globalActionsMenuId = MenuId.AuxiliaryBarTitle;169}170super(171notificationService,172storageService,173contextMenuService,174layoutService,175keybindingService,176hoverService,177instantiationService,178themeService,179Registry.as<PaneCompositeRegistry>(registryId),180activePaneCompositeSettingsKey,181viewDescriptorService.getDefaultViewContainer(location)?.id || '',182nameForTelemetry,183compositeCSSClass,184titleForegroundColor,185titleBorderColor,186partId,187partOptions188);189190this.location = location;191this.globalActionsMenuId = globalActionsMenuId;192this.registerListeners();193}194195private registerListeners(): void {196this._register(this.onDidPaneCompositeOpen(composite => this.onDidOpen(composite)));197this._register(this.onDidPaneCompositeClose(this.onDidClose, this));198199this._register(this.registry.onDidDeregister((viewletDescriptor: PaneCompositeDescriptor) => {200201const activeContainers = this.viewDescriptorService.getViewContainersByLocation(this.location)202.filter(container => this.viewDescriptorService.getViewContainerModel(container).activeViewDescriptors.length > 0);203204if (activeContainers.length) {205if (this.getActiveComposite()?.getId() === viewletDescriptor.id) {206const defaultViewletId = this.viewDescriptorService.getDefaultViewContainer(this.location)?.id;207const containerToOpen = activeContainers.filter(c => c.id === defaultViewletId)[0] || activeContainers[0];208this.doOpenPaneComposite(containerToOpen.id);209}210} else {211this.layoutService.setPartHidden(true, this.partId);212}213214this.removeComposite(viewletDescriptor.id);215}));216217this._register(this.extensionService.onDidRegisterExtensions(() => {218this.layoutCompositeBar();219}));220}221222private onDidOpen(composite: IComposite): void {223this.activePaneContextKey.set(composite.getId());224}225226private onDidClose(composite: IComposite): void {227const id = composite.getId();228if (this.activePaneContextKey.get() === id) {229this.activePaneContextKey.reset();230}231}232233protected override showComposite(composite: Composite): void {234super.showComposite(composite);235this.layoutCompositeBar();236this.layoutEmptyMessage();237}238239protected override hideActiveComposite(): Composite | undefined {240const composite = super.hideActiveComposite();241this.layoutCompositeBar();242this.layoutEmptyMessage();243return composite;244}245246override create(parent: HTMLElement): void {247this.element = parent;248this.element.classList.add('pane-composite-part');249250super.create(parent);251252const contentArea = this.getContentArea();253if (contentArea) {254this.createEmptyPaneMessage(contentArea);255}256257this.updateCompositeBar();258259const focusTracker = this._register(trackFocus(parent));260this._register(focusTracker.onDidFocus(() => this.paneFocusContextKey.set(true)));261this._register(focusTracker.onDidBlur(() => this.paneFocusContextKey.set(false)));262}263264private createEmptyPaneMessage(parent: HTMLElement): void {265this.emptyPaneMessageElement = $('.empty-pane-message-area');266267const messageElement = $('.empty-pane-message');268messageElement.textContent = localize('pane.emptyMessage', "Drag a view here to display.");269270this.emptyPaneMessageElement.appendChild(messageElement);271parent.appendChild(this.emptyPaneMessageElement);272273const setDropBackgroundFeedback = (visible: boolean) => {274const updateActivityBarBackground = !this.getActiveComposite() || !visible;275const backgroundColor = visible ? this.theme.getColor(EDITOR_DRAG_AND_DROP_BACKGROUND)?.toString() || '' : '';276277if (this.titleContainer && updateActivityBarBackground) {278this.titleContainer.style.backgroundColor = backgroundColor;279}280if (this.headerFooterCompositeBarContainer && updateActivityBarBackground) {281this.headerFooterCompositeBarContainer.style.backgroundColor = backgroundColor;282}283284this.emptyPaneMessageElement!.style.backgroundColor = backgroundColor;285};286287this._register(CompositeDragAndDropObserver.INSTANCE.registerTarget(this.element, {288onDragOver: (e) => {289EventHelper.stop(e.eventData, true);290if (this.paneCompositeBar.value) {291const validDropTarget = this.paneCompositeBar.value.dndHandler.onDragEnter(e.dragAndDropData, undefined, e.eventData);292toggleDropEffect(e.eventData.dataTransfer, 'move', validDropTarget);293}294},295onDragEnter: (e) => {296EventHelper.stop(e.eventData, true);297if (this.paneCompositeBar.value) {298const validDropTarget = this.paneCompositeBar.value.dndHandler.onDragEnter(e.dragAndDropData, undefined, e.eventData);299setDropBackgroundFeedback(validDropTarget);300}301},302onDragLeave: (e) => {303EventHelper.stop(e.eventData, true);304setDropBackgroundFeedback(false);305},306onDragEnd: (e) => {307EventHelper.stop(e.eventData, true);308setDropBackgroundFeedback(false);309},310onDrop: (e) => {311EventHelper.stop(e.eventData, true);312setDropBackgroundFeedback(false);313if (this.paneCompositeBar.value) {314this.paneCompositeBar.value.dndHandler.drop(e.dragAndDropData, undefined, e.eventData);315} else {316// Allow opening views/composites if the composite bar is hidden317const dragData = e.dragAndDropData.getData();318319if (dragData.type === 'composite') {320const currentContainer = this.viewDescriptorService.getViewContainerById(dragData.id)!;321this.viewDescriptorService.moveViewContainerToLocation(currentContainer, this.location, undefined, 'dnd');322this.openPaneComposite(currentContainer.id, true);323}324325else if (dragData.type === 'view') {326const viewToMove = this.viewDescriptorService.getViewDescriptorById(dragData.id)!;327if (viewToMove && viewToMove.canMoveView) {328this.viewDescriptorService.moveViewToLocation(viewToMove, this.location, 'dnd');329330const newContainer = this.viewDescriptorService.getViewContainerByViewId(viewToMove.id)!;331332this.openPaneComposite(newContainer.id, true).then(composite => {333composite?.openView(viewToMove.id, true);334});335}336}337}338},339}));340}341342protected override createTitleArea(parent: HTMLElement): HTMLElement {343const titleArea = super.createTitleArea(parent);344345this._register(addDisposableListener(titleArea, EventType.CONTEXT_MENU, e => {346this.onTitleAreaContextMenu(new StandardMouseEvent(getWindow(titleArea), e));347}));348this._register(Gesture.addTarget(titleArea));349this._register(addDisposableListener(titleArea, GestureEventType.Contextmenu, e => {350this.onTitleAreaContextMenu(new StandardMouseEvent(getWindow(titleArea), e));351}));352353const globalTitleActionsContainer = titleArea.appendChild($('.global-actions'));354355// Global Actions Toolbar356this.globalToolBar = this._register(this.instantiationService.createInstance(MenuWorkbenchToolBar,357globalTitleActionsContainer,358this.globalActionsMenuId,359{360actionViewItemProvider: (action, options) => this.actionViewItemProvider(action, options),361orientation: ActionsOrientation.HORIZONTAL,362getKeyBinding: action => this.keybindingService.lookupKeybinding(action.id),363anchorAlignmentProvider: () => this.getTitleAreaDropDownAnchorAlignment(),364toggleMenuTitle: localize('moreActions', "More Actions..."),365hoverDelegate: this.toolbarHoverDelegate,366hiddenItemStrategy: HiddenItemStrategy.NoHide,367highlightToggledItems: true,368telemetrySource: this.nameForTelemetry369}370));371372return titleArea;373}374375protected override createTitleLabel(parent: HTMLElement): ICompositeTitleLabel {376this.titleContainer = parent;377378const titleLabel = super.createTitleLabel(parent);379this.titleLabelElement!.draggable = true;380const draggedItemProvider = (): { type: 'view' | 'composite'; id: string } => {381const activeViewlet = this.getActivePaneComposite()!;382return { type: 'composite', id: activeViewlet.getId() };383};384this._register(CompositeDragAndDropObserver.INSTANCE.registerDraggable(this.titleLabelElement!, draggedItemProvider, {}));385386return titleLabel;387}388389protected updateCompositeBar(updateCompositeBarOption: boolean = false): void {390const wasCompositeBarVisible = this.compositeBarPosition !== undefined;391const isCompositeBarVisible = this.shouldShowCompositeBar();392const previousPosition = this.compositeBarPosition;393const newPosition = isCompositeBarVisible ? this.getCompositeBarPosition() : undefined;394395// Only update if the visibility or position has changed or if the composite bar options should be updated396if (!updateCompositeBarOption && previousPosition === newPosition) {397return;398}399400// Remove old composite bar401if (wasCompositeBarVisible) {402const previousCompositeBarContainer = previousPosition === CompositeBarPosition.TITLE ? this.titleContainer : this.headerFooterCompositeBarContainer;403if (!this.paneCompositeBarContainer || !this.paneCompositeBar.value || !previousCompositeBarContainer) {404throw new Error('Composite bar containers should exist when removing the previous composite bar');405}406407this.paneCompositeBarContainer.remove();408this.paneCompositeBarContainer = undefined;409this.paneCompositeBar.value = undefined;410411previousCompositeBarContainer.classList.remove('has-composite-bar');412413if (previousPosition === CompositeBarPosition.TOP) {414this.removeFooterHeaderArea(true);415} else if (previousPosition === CompositeBarPosition.BOTTOM) {416this.removeFooterHeaderArea(false);417}418}419420// Create new composite bar421let newCompositeBarContainer;422switch (newPosition) {423case CompositeBarPosition.TOP: newCompositeBarContainer = this.createHeaderArea(); break;424case CompositeBarPosition.TITLE: newCompositeBarContainer = this.titleContainer; break;425case CompositeBarPosition.BOTTOM: newCompositeBarContainer = this.createFooterArea(); break;426}427if (isCompositeBarVisible) {428429if (this.paneCompositeBarContainer || this.paneCompositeBar.value || !newCompositeBarContainer) {430throw new Error('Invalid composite bar state when creating the new composite bar');431}432433newCompositeBarContainer.classList.add('has-composite-bar');434this.paneCompositeBarContainer = prepend(newCompositeBarContainer, $('.composite-bar-container'));435this.paneCompositeBar.value = this.createCompositeBar();436this.paneCompositeBar.value.create(this.paneCompositeBarContainer);437438if (newPosition === CompositeBarPosition.TOP) {439this.setHeaderArea(newCompositeBarContainer);440} else if (newPosition === CompositeBarPosition.BOTTOM) {441this.setFooterArea(newCompositeBarContainer);442}443}444445this.compositeBarPosition = newPosition;446447if (updateCompositeBarOption) {448this.layoutCompositeBar();449}450}451452protected override createHeaderArea(): HTMLElement {453const headerArea = super.createHeaderArea();454455return this.createHeaderFooterCompositeBarArea(headerArea);456}457458protected override createFooterArea(): HTMLElement {459const footerArea = super.createFooterArea();460461return this.createHeaderFooterCompositeBarArea(footerArea);462}463464protected createHeaderFooterCompositeBarArea(area: HTMLElement): HTMLElement {465if (this.headerFooterCompositeBarContainer) {466// A pane composite part has either a header or a footer, but not both467throw new Error('Header or Footer composite bar already exists');468}469this.headerFooterCompositeBarContainer = area;470471this.headerFooterCompositeBarDispoables.add(addDisposableListener(area, EventType.CONTEXT_MENU, e => {472this.onCompositeBarAreaContextMenu(new StandardMouseEvent(getWindow(area), e));473}));474this.headerFooterCompositeBarDispoables.add(Gesture.addTarget(area));475this.headerFooterCompositeBarDispoables.add(addDisposableListener(area, GestureEventType.Contextmenu, e => {476this.onCompositeBarAreaContextMenu(new StandardMouseEvent(getWindow(area), e));477}));478479return area;480}481482private removeFooterHeaderArea(header: boolean): void {483this.headerFooterCompositeBarContainer = undefined;484this.headerFooterCompositeBarDispoables.clear();485if (header) {486this.removeHeaderArea();487} else {488this.removeFooterArea();489}490}491492protected createCompositeBar(): PaneCompositeBar {493return this.instantiationService.createInstance(PaneCompositeBar, this.getCompositeBarOptions(), this.partId, this);494}495496protected override onTitleAreaUpdate(compositeId: string): void {497super.onTitleAreaUpdate(compositeId);498499// If title actions change, relayout the composite bar500this.layoutCompositeBar();501}502503async openPaneComposite(id?: string, focus?: boolean): Promise<PaneComposite | undefined> {504if (typeof id === 'string' && this.getPaneComposite(id)) {505return this.doOpenPaneComposite(id, focus);506}507508await this.extensionService.whenInstalledExtensionsRegistered();509510if (typeof id === 'string' && this.getPaneComposite(id)) {511return this.doOpenPaneComposite(id, focus);512}513514return undefined;515}516517private async doOpenPaneComposite(id: string, focus?: boolean): Promise<PaneComposite | undefined> {518if (this.blockOpening) {519// Workaround against a potential race condition when calling520// `setPartHidden` we may end up in `openPaneComposite` again.521// But we still want to return the result of the original call,522// so we return the promise of the original call.523return this.blockOpening.p;524}525526let blockOpening: DeferredPromise<PaneComposite | undefined> | undefined;527if (!this.layoutService.isVisible(this.partId)) {528try {529blockOpening = this.blockOpening = new DeferredPromise<PaneComposite | undefined>();530this.layoutService.setPartHidden(false, this.partId);531} finally {532this.blockOpening = undefined;533}534}535536try {537const result = this.openComposite(id, focus) as PaneComposite | undefined;538blockOpening?.complete(result);539540return result;541} catch (error) {542blockOpening?.error(error);543throw error;544}545}546547getPaneComposite(id: string): PaneCompositeDescriptor | undefined {548return (this.registry as PaneCompositeRegistry).getPaneComposite(id);549}550551getPaneComposites(): PaneCompositeDescriptor[] {552return (this.registry as PaneCompositeRegistry).getPaneComposites()553.sort((v1, v2) => {554if (typeof v1.order !== 'number') {555return 1;556}557558if (typeof v2.order !== 'number') {559return -1;560}561562return v1.order - v2.order;563});564}565566getPinnedPaneCompositeIds(): string[] {567return this.paneCompositeBar.value?.getPinnedPaneCompositeIds() ?? [];568}569570getVisiblePaneCompositeIds(): string[] {571return this.paneCompositeBar.value?.getVisiblePaneCompositeIds() ?? [];572}573574getPaneCompositeIds(): string[] {575return this.paneCompositeBar.value?.getPaneCompositeIds() ?? [];576}577578getActivePaneComposite(): IPaneComposite | undefined {579return <IPaneComposite>this.getActiveComposite();580}581582getLastActivePaneCompositeId(): string {583return this.getLastActiveCompositeId();584}585586hideActivePaneComposite(): void {587if (this.layoutService.isVisible(this.partId)) {588this.layoutService.setPartHidden(true, this.partId);589}590591this.hideActiveComposite();592}593594protected focusCompositeBar(): void {595this.paneCompositeBar.value?.focus();596}597598override layout(width: number, height: number, top: number, left: number): void {599if (!this.layoutService.isVisible(this.partId)) {600return;601}602603this.contentDimension = new Dimension(width, height);604605// Layout contents606super.layout(this.contentDimension.width, this.contentDimension.height, top, left);607608// Layout composite bar609this.layoutCompositeBar();610611// Add empty pane message612this.layoutEmptyMessage();613}614615private layoutCompositeBar(): void {616if (this.contentDimension && this.dimension && this.paneCompositeBar.value) {617const padding = this.compositeBarPosition === CompositeBarPosition.TITLE ? 16 : 8;618const borderWidth = this.partId === Parts.PANEL_PART ? 0 : 1;619let availableWidth = this.contentDimension.width - padding - borderWidth;620availableWidth = Math.max(AbstractPaneCompositePart.MIN_COMPOSITE_BAR_WIDTH, availableWidth - this.getToolbarWidth());621this.paneCompositeBar.value.layout(availableWidth, this.dimension.height);622}623}624625private layoutEmptyMessage(): void {626const visible = !this.getActiveComposite();627this.element.classList.toggle('empty', visible);628if (visible) {629this.titleLabel?.updateTitle('', '');630}631}632633protected getToolbarWidth(): number {634if (!this.toolBar || this.compositeBarPosition !== CompositeBarPosition.TITLE) {635return 0;636}637638const activePane = this.getActivePaneComposite();639if (!activePane) {640return 0;641}642643// Each toolbar item has 4px margin644const toolBarWidth = this.toolBar.getItemsWidth() + this.toolBar.getItemsLength() * 4;645const globalToolBarWidth = this.globalToolBar ? this.globalToolBar.getItemsWidth() + this.globalToolBar.getItemsLength() * 4 : 0;646return toolBarWidth + globalToolBarWidth + 5; // 5px padding left647}648649private onTitleAreaContextMenu(event: StandardMouseEvent): void {650if (this.shouldShowCompositeBar() && this.getCompositeBarPosition() === CompositeBarPosition.TITLE) {651return this.onCompositeBarContextMenu(event);652} else {653const activePaneComposite = this.getActivePaneComposite() as PaneComposite;654const activePaneCompositeActions = activePaneComposite ? activePaneComposite.getContextMenuActions() : [];655if (activePaneCompositeActions.length) {656this.contextMenuService.showContextMenu({657getAnchor: () => event,658getActions: () => activePaneCompositeActions,659getActionViewItem: (action, options) => this.actionViewItemProvider(action, options),660actionRunner: activePaneComposite.getActionRunner(),661skipTelemetry: true662});663}664}665}666667private onCompositeBarAreaContextMenu(event: StandardMouseEvent): void {668return this.onCompositeBarContextMenu(event);669}670671private onCompositeBarContextMenu(event: StandardMouseEvent): void {672if (this.paneCompositeBar.value) {673const actions: IAction[] = [...this.paneCompositeBar.value.getContextMenuActions()];674if (actions.length) {675this.contextMenuService.showContextMenu({676getAnchor: () => event,677getActions: () => actions,678skipTelemetry: true679});680}681}682}683684protected getViewsSubmenuAction(): SubmenuAction | undefined {685const viewPaneContainer = (this.getActivePaneComposite() as PaneComposite)?.getViewPaneContainer();686if (viewPaneContainer) {687const disposables = new DisposableStore();688const scopedContextKeyService = disposables.add(this.contextKeyService.createScoped(this.element));689scopedContextKeyService.createKey('viewContainer', viewPaneContainer.viewContainer.id);690const menu = this.menuService.getMenuActions(ViewsSubMenu, scopedContextKeyService, { shouldForwardArgs: true, renderShortTitle: true });691const viewsActions = getActionBarActions(menu, () => true).primary;692disposables.dispose();693return viewsActions.length > 1 && viewsActions.some(a => a.enabled) ? new SubmenuAction('views', localize('views', "Views"), viewsActions) : undefined;694}695return undefined;696}697698protected abstract shouldShowCompositeBar(): boolean;699protected abstract getCompositeBarOptions(): IPaneCompositeBarOptions;700protected abstract getCompositeBarPosition(): CompositeBarPosition;701}702703704