From 56b8c192051b277ed775332ae24a0ab3425e2947 Mon Sep 17 00:00:00 2001 From: SteVen Batten Date: Mon, 11 May 2020 11:42:18 -0700 Subject: [PATCH] support contextual title via containerTitle --- .../api/browser/viewsExtensionPoint.ts | 1 + .../browser/parts/panel/panelPart.ts | 60 ++++++++++++++++++- .../browser/parts/views/viewPaneContainer.ts | 27 +++++++-- src/vs/workbench/common/views.ts | 2 + .../views/common/viewContainerModel.ts | 2 +- 5 files changed, 84 insertions(+), 8 deletions(-) diff --git a/src/vs/workbench/api/browser/viewsExtensionPoint.ts b/src/vs/workbench/api/browser/viewsExtensionPoint.ts index 46bf7934fd0..ce84fd5028b 100644 --- a/src/vs/workbench/api/browser/viewsExtensionPoint.ts +++ b/src/vs/workbench/api/browser/viewsExtensionPoint.ts @@ -412,6 +412,7 @@ class ViewsExtensionHandler implements IWorkbenchContribution { ctorDescriptor: new SyncDescriptor(TreeViewPane), when: ContextKeyExpr.deserialize(item.when), containerIcon: viewContainer?.icon, + containerTitle: viewContainer?.name, canToggleVisibility: true, canMoveView: true, treeView: this.instantiationService.createInstance(CustomTreeView, item.id, item.name), diff --git a/src/vs/workbench/browser/parts/panel/panelPart.ts b/src/vs/workbench/browser/parts/panel/panelPart.ts index e03c9f0ea32..2be7d5f6734 100644 --- a/src/vs/workbench/browser/parts/panel/panelPart.ts +++ b/src/vs/workbench/browser/parts/panel/panelPart.ts @@ -50,11 +50,17 @@ interface ICachedPanel { views?: { when?: string }[]; } +interface IPlaceholderViewContainer { + id: string; + name?: string; +} + export class PanelPart extends CompositePart implements IPanelService { static readonly activePanelSettingsKey = 'workbench.panelpart.activepanelid'; static readonly PINNED_PANELS = 'workbench.panel.pinnedPanels'; + static readonly PLACEHOLDER_VIEW_CONTAINERS = 'workbench.panel.placeholderPanels'; private static readonly MIN_COMPOSITE_BAR_WIDTH = 50; _serviceBrand: undefined; @@ -94,6 +100,8 @@ export class PanelPart extends CompositePart implements IPanelService { private blockOpeningPanel = false; private contentDimension: Dimension | undefined; + private extensionsRegistered = false; + private panelRegistry: PanelRegistry; private dndHandler: ICompositeDragAndDrop; @@ -255,9 +263,11 @@ export class PanelPart extends CompositePart implements IPanelService { } private updateActivity(viewContainer: ViewContainer, viewContainerModel: IViewContainerModel): void { + const cachedTitle = this.getPlaceholderViewContainers().filter(panel => panel.id === viewContainer.id)[0]?.name; + const activity: IActivity = { id: viewContainer.id, - name: viewContainerModel.title, + name: this.extensionsRegistered || cachedTitle === undefined ? viewContainerModel.title : cachedTitle, keybindingId: viewContainer.focusCommand?.id }; @@ -268,7 +278,10 @@ export class PanelPart extends CompositePart implements IPanelService { pinnedAction.setActivity(activity); } - this.saveCachedPanels(); + // only update our cached panel info after extensions are done registering + if (this.extensionsRegistered) { + this.saveCachedPanels(); + } } private onDidChangeActiveViews(viewContainer: ViewContainer, viewContainerModel: IViewContainerModel): void { @@ -313,6 +326,7 @@ export class PanelPart extends CompositePart implements IPanelService { } private onDidRegisterExtensions(): void { + this.extensionsRegistered = true; this.removeNotExistingComposites(); this.saveCachedPanels(); @@ -670,6 +684,7 @@ export class PanelPart extends CompositePart implements IPanelService { private saveCachedPanels(): void { const state: ICachedPanel[] = []; + const placeholders: IPlaceholderViewContainer[] = []; const compositeItems = this.compositeBar.getCompositeBarItems(); for (const compositeItem of compositeItems) { @@ -677,10 +692,12 @@ export class PanelPart extends CompositePart implements IPanelService { if (viewContainer) { const viewContainerModel = this.viewDescriptorService.getViewContainerModel(viewContainer); state.push({ id: compositeItem.id, name: viewContainerModel.title, pinned: compositeItem.pinned, order: compositeItem.order, visible: compositeItem.visible }); + placeholders.push({ id: compositeItem.id, name: this.getCompositeActions(compositeItem.id).activityAction.label }); } } this.cachedPanelsValue = JSON.stringify(state); + this.setPlaceholderViewContainers(placeholders); } private getCachedPanels(): ICachedPanel[] { @@ -694,6 +711,13 @@ export class PanelPart extends CompositePart implements IPanelService { return serialized; }); + for (const placeholderViewContainer of this.getPlaceholderViewContainers()) { + const cachedViewContainer = cachedPanels.filter(cached => cached.id === placeholderViewContainer.id)[0]; + if (cachedViewContainer) { + cachedViewContainer.name = placeholderViewContainer.name; + } + } + return cachedPanels; } @@ -721,6 +745,38 @@ export class PanelPart extends CompositePart implements IPanelService { this.storageService.store(PanelPart.PINNED_PANELS, value, StorageScope.GLOBAL); } + private getPlaceholderViewContainers(): IPlaceholderViewContainer[] { + return JSON.parse(this.placeholderViewContainersValue); + } + + private setPlaceholderViewContainers(placeholderViewContainers: IPlaceholderViewContainer[]): void { + this.placeholderViewContainersValue = JSON.stringify(placeholderViewContainers); + } + + private _placeholderViewContainersValue: string | undefined; + private get placeholderViewContainersValue(): string { + if (!this._placeholderViewContainersValue) { + this._placeholderViewContainersValue = this.getStoredPlaceholderViewContainersValue(); + } + + return this._placeholderViewContainersValue; + } + + private set placeholderViewContainersValue(placeholderViewContainesValue: string) { + if (this.placeholderViewContainersValue !== placeholderViewContainesValue) { + this._placeholderViewContainersValue = placeholderViewContainesValue; + this.setStoredPlaceholderViewContainersValue(placeholderViewContainesValue); + } + } + + private getStoredPlaceholderViewContainersValue(): string { + return this.storageService.get(PanelPart.PLACEHOLDER_VIEW_CONTAINERS, StorageScope.WORKSPACE, '[]'); + } + + private setStoredPlaceholderViewContainersValue(value: string): void { + this.storageService.store(PanelPart.PLACEHOLDER_VIEW_CONTAINERS, value, StorageScope.WORKSPACE); + } + private getViewContainer(panelId: string): ViewContainer | undefined { return this.viewDescriptorService.getViewContainerById(panelId) || undefined; } diff --git a/src/vs/workbench/browser/parts/views/viewPaneContainer.ts b/src/vs/workbench/browser/parts/views/viewPaneContainer.ts index 2b2881698f2..7234e7f5b5e 100644 --- a/src/vs/workbench/browser/parts/views/viewPaneContainer.ts +++ b/src/vs/workbench/browser/parts/views/viewPaneContainer.ts @@ -290,6 +290,10 @@ export abstract class ViewPane extends Pane implements IView { this._register(this.toolbar); this.setActions(); + this._register(this.viewDescriptorService.getViewContainerModel(this.viewDescriptorService.getViewContainerByViewId(this.id)!)!.onDidChangeContainerInfo(({ title }) => { + this.updateTitle(this.title); + })); + const onDidRelevantConfigurationChange = Event.filter(this.configurationService.onDidChangeConfiguration, e => e.affectsConfiguration(ViewPane.AlwaysShowActionsConfig)); this._register(onDidRelevantConfigurationChange(this.updateActionsVisibility, this)); this.updateActionsVisibility(); @@ -300,17 +304,30 @@ export abstract class ViewPane extends Pane implements IView { } protected renderHeaderTitle(container: HTMLElement, title: string): void { - this.titleContainer = append(container, $('h3.title', undefined, title)); + this.titleContainer = append(container, $('h3.title', undefined, this.calculateTitle(title))); } - protected updateTitle(title: string): void { + updateTitle(title: string): void { if (this.titleContainer) { - this.titleContainer.textContent = title; + this.titleContainer.textContent = this.calculateTitle(title); } this.title = title; this._onDidChangeTitleArea.fire(); } + private calculateTitle(title: string): string { + const viewContainer = this.viewDescriptorService.getViewContainerByViewId(this.id)!; + const model = this.viewDescriptorService.getViewContainerModel(viewContainer); + const viewDescriptor = this.viewDescriptorService.getViewDescriptorById(this.id)!; + const isDefault = this.viewDescriptorService.getDefaultContainerById(this.id) === viewContainer; + + if (!isDefault && viewDescriptor.containerTitle && model.title !== viewDescriptor.containerTitle) { + return `${viewDescriptor.containerTitle}: ${title}`; + } + + return title; + } + private scrollableElement!: DomScrollableElement; protected renderBody(container: HTMLElement): void { @@ -510,7 +527,6 @@ export abstract class ViewPane extends Pane implements IView { export interface IViewPaneContainerOptions extends IPaneViewOptions { mergeViewWithContainerWhenSingleView: boolean; - donotShowContainerTitleWhenMergedWithContainer?: boolean; } interface IViewPaneItem { @@ -904,7 +920,7 @@ export class ViewPaneContainer extends Component implements IViewPaneContainer { if (this.isViewMergedWithContainer()) { const paneItemTitle = this.paneItems[0].pane.title; - if (this.options.donotShowContainerTitleWhenMergedWithContainer || containerTitle === paneItemTitle) { + if (containerTitle === paneItemTitle) { return this.paneItems[0].pane.title; } return paneItemTitle ? `${containerTitle}: ${paneItemTitle}` : containerTitle; @@ -1227,6 +1243,7 @@ export class ViewPaneContainer extends Component implements IViewPaneContainer { this.updateTitleArea(); } }); + const onDidChangeVisibility = pane.onDidChangeBodyVisibility(() => this._onDidChangeViewVisibility.fire(pane)); const onDidChange = pane.onDidChange(() => { if (pane === this.lastFocusedPane && !pane.isExpanded()) { diff --git a/src/vs/workbench/common/views.ts b/src/vs/workbench/common/views.ts index c8bffe666da..6b7a1506c99 100644 --- a/src/vs/workbench/common/views.ts +++ b/src/vs/workbench/common/views.ts @@ -211,6 +211,8 @@ export interface IViewDescriptor { readonly containerIcon?: string | URI; + readonly containerTitle?: string; + // Applies only to newly created views readonly hideByDefault?: boolean; diff --git a/src/vs/workbench/services/views/common/viewContainerModel.ts b/src/vs/workbench/services/views/common/viewContainerModel.ts index 3feced17fa1..22a0bee904a 100644 --- a/src/vs/workbench/services/views/common/viewContainerModel.ts +++ b/src/vs/workbench/services/views/common/viewContainerModel.ts @@ -342,7 +342,7 @@ export class ViewContainerModel extends Disposable implements IViewContainerMode private updateContainerInfo(): void { /* Use default container info if one of the visible view descriptors belongs to the current container by default */ const useDefaultContainerInfo = this.container.alwaysUseContainerInfo || this.visibleViewDescriptors.length === 0 || this.visibleViewDescriptors.some(v => Registry.as(ViewExtensions.ViewsRegistry).getViewContainer(v.id) === this.container); - const title = useDefaultContainerInfo ? this.container.name : this.visibleViewDescriptors[0]?.name || ''; + const title = useDefaultContainerInfo ? this.container.name : this.visibleViewDescriptors[0]?.containerTitle || this.visibleViewDescriptors[0]?.name || ''; let titleChanged: boolean = false; if (this._title !== title) { this._title = title; -- GitLab