Skip to content

Commit d60bf23

Browse files
committed
microsoft#89993 Enhance views service
- register viewlets and panels for containers - events when view visibility has changed - small refactorings
1 parent 7acda4b commit d60bf23

7 files changed

Lines changed: 141 additions & 110 deletions

File tree

src/vs/workbench/browser/parts/views/viewPaneContainer.ts

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -293,6 +293,14 @@ export class ViewPaneContainer extends Component implements IViewPaneContainer {
293293
private readonly _onDidChangeVisibility = this._register(new Emitter<boolean>());
294294
readonly onDidChangeVisibility = this._onDidChangeVisibility.event;
295295

296+
private readonly _onDidAddViews = this._register(new Emitter<IView[]>());
297+
readonly onDidAddViews = this._onDidAddViews.event;
298+
299+
private readonly _onDidRemoveViews = this._register(new Emitter<IView[]>());
300+
readonly onDidRemoveViews = this._onDidRemoveViews.event;
301+
302+
private readonly _onDidChangeViewVisibility = this._register(new Emitter<IView>());
303+
readonly onDidChangeViewVisibility = this._onDidChangeViewVisibility.event;
296304

297305
get onDidSashChange(): Event<number> {
298306
return assertIsDefined(this.paneview).onDidSashChange;
@@ -347,15 +355,15 @@ export class ViewPaneContainer extends Component implements IViewPaneContainer {
347355
this._register(addDisposableListener(parent, EventType.CONTEXT_MENU, (e: MouseEvent) => this.showContextMenu(new StandardMouseEvent(e))));
348356

349357
this._register(this.onDidSashChange(() => this.saveViewSizes()));
350-
this.viewsModel.onDidAdd(added => this.onDidAddViews(added));
351-
this.viewsModel.onDidRemove(removed => this.onDidRemoveViews(removed));
358+
this.viewsModel.onDidAdd(added => this.onDidAddViewDescriptors(added));
359+
this.viewsModel.onDidRemove(removed => this.onDidRemoveViewDescriptors(removed));
352360
const addedViews: IAddedViewDescriptorRef[] = this.viewsModel.visibleViewDescriptors.map((viewDescriptor, index) => {
353361
const size = this.viewsModel.getSize(viewDescriptor.id);
354362
const collapsed = this.viewsModel.isCollapsed(viewDescriptor.id);
355363
return ({ viewDescriptor, index, size, collapsed });
356364
});
357365
if (addedViews.length) {
358-
this.onDidAddViews(addedViews);
366+
this.onDidAddViewDescriptors(addedViews);
359367
}
360368

361369
// Update headers after and title contributed views after available, since we read from cache in the beginning to know if the viewlet has single view or not. Ref #29609
@@ -503,6 +511,8 @@ export class ViewPaneContainer extends Component implements IViewPaneContainer {
503511
if (this.isViewMergedWithContainer() !== wasMerged) {
504512
this.updateTitleArea();
505513
}
514+
515+
this._onDidAddViews.fire(panes.map(({ pane }) => pane));
506516
}
507517

508518
setVisible(visible: boolean): void {
@@ -606,7 +616,7 @@ export class ViewPaneContainer extends Component implements IViewPaneContainer {
606616
return view;
607617
}
608618

609-
protected onDidAddViews(added: IAddedViewDescriptorRef[]): ViewPane[] {
619+
protected onDidAddViewDescriptors(added: IAddedViewDescriptorRef[]): ViewPane[] {
610620
const panesToAdd: { pane: ViewPane, size: number, index: number }[] = [];
611621

612622
for (const { viewDescriptor, collapsed, index, size } of added) {
@@ -653,7 +663,7 @@ export class ViewPaneContainer extends Component implements IViewPaneContainer {
653663
return this.actionRunner;
654664
}
655665

656-
private onDidRemoveViews(removed: IViewDescriptorRef[]): void {
666+
private onDidRemoveViewDescriptors(removed: IViewDescriptorRef[]): void {
657667
removed = removed.sort((a, b) => b.index - a.index);
658668
const panesToRemove: ViewPane[] = [];
659669
for (const { index } of removed) {
@@ -682,6 +692,7 @@ export class ViewPaneContainer extends Component implements IViewPaneContainer {
682692
this.updateTitleArea();
683693
}
684694
});
695+
const onDidChangeVisibility = pane.onDidChangeBodyVisibility(() => this._onDidChangeViewVisibility.fire(pane));
685696
const onDidChange = pane.onDidChange(() => {
686697
if (pane === this.lastFocusedPane && !pane.isExpanded()) {
687698
this.lastFocusedPane = undefined;
@@ -695,7 +706,7 @@ export class ViewPaneContainer extends Component implements IViewPaneContainer {
695706
headerBorder: SIDE_BAR_SECTION_HEADER_BORDER,
696707
dropBackground: SIDE_BAR_DRAG_AND_DROP_BACKGROUND
697708
}, pane);
698-
const disposable = combinedDisposable(onDidFocus, onDidChangeTitleArea, paneStyler, onDidChange);
709+
const disposable = combinedDisposable(onDidFocus, onDidChangeTitleArea, paneStyler, onDidChange, onDidChangeVisibility);
699710
const paneItem: IViewPaneItem = { pane: pane, disposable };
700711

701712
this.paneItems.splice(index, 0, paneItem);
@@ -711,6 +722,8 @@ export class ViewPaneContainer extends Component implements IViewPaneContainer {
711722
if (wasMerged !== this.isViewMergedWithContainer()) {
712723
this.updateTitleArea();
713724
}
725+
726+
this._onDidRemoveViews.fire(panes);
714727
}
715728

716729
private removePane(pane: ViewPane): void {

src/vs/workbench/browser/parts/views/views.ts

Lines changed: 104 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet';
1212
import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
1313
import { Event, Emitter } from 'vs/base/common/event';
1414
import { firstIndex, move } from 'vs/base/common/arrays';
15-
import { isUndefinedOrNull, isUndefined } from 'vs/base/common/types';
15+
import { isUndefinedOrNull, isUndefined, isString } from 'vs/base/common/types';
1616
import { MenuId, registerAction2, Action2 } from 'vs/platform/actions/common/actions';
1717
import { localize } from 'vs/nls';
1818
import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
@@ -22,9 +22,19 @@ import { toggleClass, addClass } from 'vs/base/browser/dom';
2222
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
2323
import { IPaneComposite } from 'vs/workbench/common/panecomposite';
2424
import { IPanelService } from 'vs/workbench/services/panel/common/panelService';
25-
import type { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
26-
import { PaneComposite } from 'vs/workbench/browser/panecomposite';
25+
import { ServicesAccessor, IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
2726
import { VIEW_ID as SEARCH_VIEW_ID } from 'vs/workbench/services/search/common/search';
27+
import { ViewPaneContainer } from 'vs/workbench/browser/parts/views/viewPaneContainer';
28+
import { PaneCompositePanel, PanelRegistry, PanelDescriptor, Extensions as PanelExtensions } from 'vs/workbench/browser/panel';
29+
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
30+
import { IThemeService } from 'vs/platform/theme/common/themeService';
31+
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
32+
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
33+
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
34+
import { Viewlet, ViewletDescriptor, ViewletRegistry, Extensions as ViewletExtensions } from 'vs/workbench/browser/viewlet';
35+
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
36+
import { IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService';
37+
import { URI } from 'vs/base/common/uri';
2838

2939
export interface IViewState {
3040
visibleGlobal: boolean | undefined;
@@ -451,10 +461,14 @@ export class ViewsService extends Disposable implements IViewsService {
451461
private readonly viewContainersRegistry: IViewContainersRegistry;
452462
private readonly viewDisposable: Map<IViewDescriptor, IDisposable>;
453463

464+
private readonly _onDidChangeViewVisibility: Emitter<{ id: string, visible: boolean }> = this._register(new Emitter<{ id: string, visible: boolean }>());
465+
readonly onDidChangeViewVisibility: Event<{ id: string, visible: boolean }> = this._onDidChangeViewVisibility.event;
466+
454467
constructor(
455468
@IViewDescriptorService private readonly viewDescriptorService: IViewDescriptorService,
456469
@IPanelService private readonly panelService: IPanelService,
457-
@IViewletService private readonly viewletService: IViewletService
470+
@IViewletService private readonly viewletService: IViewletService,
471+
@IInstantiationService private readonly instantiationService: IInstantiationService,
458472
) {
459473
super();
460474

@@ -466,11 +480,11 @@ export class ViewsService extends Disposable implements IViewsService {
466480
this.viewDisposable.clear();
467481
}));
468482

469-
this.viewContainersRegistry.all.forEach(viewContainer => this.onViewContainerRegistered(viewContainer));
470-
this._register(this.viewContainersRegistry.onDidRegister(({ viewContainer }) => this.onViewContainerRegistered(viewContainer)));
483+
this.viewContainersRegistry.all.forEach(viewContainer => this.onDidRegisterViewContainer(viewContainer, this.viewContainersRegistry.getViewContainerLocation(viewContainer)));
484+
this._register(this.viewContainersRegistry.onDidRegister(({ viewContainer, viewContainerLocation }) => this.onDidRegisterViewContainer(viewContainer, viewContainerLocation)));
471485
}
472486

473-
private onViewContainerRegistered(viewContainer: ViewContainer): void {
487+
private onDidRegisterViewContainer(viewContainer: ViewContainer, location: ViewContainerLocation): void {
474488
const viewDescriptorCollection = this.viewDescriptorService.getViewDescriptors(viewContainer);
475489
this.onViewsAdded(viewDescriptorCollection.allViewDescriptors, viewContainer);
476490
this._register(viewDescriptorCollection.onDidChangeViews(({ added, removed }) => {
@@ -577,20 +591,20 @@ export class ViewsService extends Disposable implements IViewsService {
577591
return undefined;
578592
}
579593

580-
getActiveViewWithId(id: string): IView | null {
594+
getActiveViewWithId<T extends IView>(id: string): T | null {
581595
const viewContainer = this.viewDescriptorService.getViewContainer(id);
582596
if (viewContainer) {
583597
const location = this.viewContainersRegistry.getViewContainerLocation(viewContainer);
584598

585599
if (location === ViewContainerLocation.Sidebar) {
586600
const activeViewlet = this.viewletService.getActiveViewlet();
587601
if (activeViewlet?.getId() === viewContainer.id) {
588-
return activeViewlet.getViewPaneContainer().getView(id) ?? null;
602+
return activeViewlet.getViewPaneContainer().getView(id) as T ?? null;
589603
}
590604
} else if (location === ViewContainerLocation.Panel) {
591605
const activePanel = this.panelService.getActivePanel();
592-
if (activePanel?.getId() === viewContainer.id && activePanel instanceof PaneComposite) {
593-
return activePanel.getViewPaneContainer().getView(id) ?? null;
606+
if (activePanel?.getId() === viewContainer.id) {
607+
return (activePanel as IPaneComposite).getViewPaneContainer().getView(id) as T ?? null;
594608
}
595609
}
596610
}
@@ -613,6 +627,14 @@ export class ViewsService extends Disposable implements IViewsService {
613627

614628
return null;
615629
}
630+
631+
createContainer(container: ViewContainer): ViewPaneContainer {
632+
const viewPaneContainer: ViewPaneContainer = this._register((this.instantiationService as any).createInstance(container.ctorDescriptor!.ctor, ...(container.ctorDescriptor!.staticArguments || [])));
633+
this._register(viewPaneContainer.onDidAddViews(views => views.forEach(view => this._onDidChangeViewVisibility.fire({ id: view.id, visible: view.isBodyVisible() }))));
634+
this._register(viewPaneContainer.onDidChangeViewVisibility(view => this._onDidChangeViewVisibility.fire({ id: view.id, visible: view.isBodyVisible() })));
635+
this._register(viewPaneContainer.onDidRemoveViews(views => views.forEach(view => this._onDidChangeViewVisibility.fire({ id: view.id, visible: false }))));
636+
return viewPaneContainer;
637+
}
616638
}
617639

618640
export function createFileIconThemableTreeContainerScope(container: HTMLElement, themeService: IWorkbenchThemeService): IDisposable {
@@ -629,3 +651,74 @@ export function createFileIconThemableTreeContainerScope(container: HTMLElement,
629651
}
630652

631653
registerSingleton(IViewsService, ViewsService);
654+
655+
// Viewlets & Panels
656+
(function registerViewletsAndPanels(): void {
657+
const registerPanel = (viewContainer: ViewContainer): void => {
658+
class PaneContainerPanel extends PaneCompositePanel {
659+
constructor(
660+
@ITelemetryService telemetryService: ITelemetryService,
661+
@IStorageService storageService: IStorageService,
662+
@IInstantiationService instantiationService: IInstantiationService,
663+
@IThemeService themeService: IThemeService,
664+
@IContextMenuService contextMenuService: IContextMenuService,
665+
@IExtensionService extensionService: IExtensionService,
666+
@IWorkspaceContextService contextService: IWorkspaceContextService,
667+
@IViewsService viewsService: ViewsService
668+
) {
669+
super(viewContainer.id, viewsService.createContainer(viewContainer), telemetryService, storageService, instantiationService, themeService, contextMenuService, extensionService, contextService);
670+
}
671+
}
672+
Registry.as<PanelRegistry>(PanelExtensions.Panels).registerPanel(PanelDescriptor.create(
673+
PaneContainerPanel,
674+
viewContainer.id,
675+
viewContainer.name,
676+
isString(viewContainer.icon) ? viewContainer.icon : undefined,
677+
viewContainer.order,
678+
viewContainer.focusCommand?.id,
679+
));
680+
};
681+
682+
const registerViewlet = (viewContainer: ViewContainer): void => {
683+
class PaneContainerViewlet extends Viewlet {
684+
constructor(
685+
@IConfigurationService configurationService: IConfigurationService,
686+
@IWorkbenchLayoutService layoutService: IWorkbenchLayoutService,
687+
@ITelemetryService telemetryService: ITelemetryService,
688+
@IWorkspaceContextService contextService: IWorkspaceContextService,
689+
@IStorageService storageService: IStorageService,
690+
@IInstantiationService instantiationService: IInstantiationService,
691+
@IThemeService themeService: IThemeService,
692+
@IContextMenuService contextMenuService: IContextMenuService,
693+
@IExtensionService extensionService: IExtensionService
694+
) {
695+
super(viewContainer.id, (instantiationService as any).createInstance(viewContainer.ctorDescriptor!.ctor, ...(viewContainer.ctorDescriptor!.staticArguments || [])), telemetryService, storageService, instantiationService, themeService, contextMenuService, extensionService, contextService, layoutService, configurationService);
696+
}
697+
}
698+
const viewletDescriptor = ViewletDescriptor.create(
699+
PaneContainerViewlet,
700+
viewContainer.id,
701+
viewContainer.name,
702+
isString(viewContainer.icon) ? viewContainer.icon : undefined,
703+
viewContainer.order,
704+
viewContainer.icon instanceof URI ? viewContainer.icon : undefined
705+
);
706+
707+
Registry.as<ViewletRegistry>(ViewletExtensions.Viewlets).registerViewlet(viewletDescriptor);
708+
};
709+
710+
const viewContainerRegistry = Registry.as<IViewContainersRegistry>(ViewExtensions.ViewContainersRegistry);
711+
viewContainerRegistry.getViewContainers(ViewContainerLocation.Panel).forEach(viewContainer => registerPanel(viewContainer));
712+
viewContainerRegistry.onDidRegister(({ viewContainer, viewContainerLocation }) => {
713+
switch (viewContainerLocation) {
714+
case ViewContainerLocation.Panel:
715+
registerPanel(viewContainer);
716+
return;
717+
case ViewContainerLocation.Sidebar:
718+
if (viewContainer.ctorDescriptor) {
719+
registerViewlet(viewContainer);
720+
}
721+
return;
722+
}
723+
});
724+
})();

src/vs/workbench/browser/parts/views/viewsViewlet.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -130,8 +130,8 @@ export abstract class FilterViewPaneContainer extends ViewPaneContainer {
130130
return views;
131131
}
132132

133-
onDidAddViews(added: IAddedViewDescriptorRef[]): ViewPane[] {
134-
const panes: ViewPane[] = super.onDidAddViews(added);
133+
onDidAddViewDescriptors(added: IAddedViewDescriptorRef[]): ViewPane[] {
134+
const panes: ViewPane[] = super.onDidAddViewDescriptors(added);
135135
for (let i = 0; i < added.length; i++) {
136136
if (this.constantViewDescriptors.has(added[i].viewDescriptor.id)) {
137137
panes[i].setExpanded(false);

src/vs/workbench/browser/workbench.contribution.ts

Lines changed: 0 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -8,21 +8,6 @@ import * as nls from 'vs/nls';
88
import { IConfigurationRegistry, Extensions as ConfigurationExtensions, ConfigurationScope } from 'vs/platform/configuration/common/configurationRegistry';
99
import { isMacintosh, isWindows, isLinux, isWeb, isNative } from 'vs/base/common/platform';
1010
import { workbenchConfigurationNodeBase } from 'vs/workbench/common/configuration';
11-
import { PanelRegistry, Extensions as PanelExtensions, PanelDescriptor, PaneCompositePanel } from 'vs/workbench/browser/panel';
12-
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
13-
import { IStorageService } from 'vs/platform/storage/common/storage';
14-
import { ViewContainer, IViewContainersRegistry, Extensions as ViewContainerExtensions, ViewContainerLocation } from 'vs/workbench/common/views';
15-
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
16-
import { IThemeService } from 'vs/platform/theme/common/themeService';
17-
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
18-
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
19-
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
20-
import { Viewlet, ViewletDescriptor, ViewletRegistry, Extensions as ViewletExtensions } from 'vs/workbench/browser/viewlet';
21-
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
22-
import { IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService';
23-
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
24-
import { isString } from 'vs/base/common/types';
25-
import { URI } from 'vs/base/common/uri';
2611

2712
// Configuration
2813
(function registerConfiguration(): void {
@@ -393,74 +378,3 @@ import { URI } from 'vs/base/common/uri';
393378
}
394379
});
395380
})();
396-
397-
// Viewlets & Panels
398-
(function registerViewletsAndPanels(): void {
399-
const registerPanel = (viewContainer: ViewContainer): void => {
400-
class PaneContainerPanel extends PaneCompositePanel {
401-
constructor(
402-
@ITelemetryService telemetryService: ITelemetryService,
403-
@IStorageService storageService: IStorageService,
404-
@IInstantiationService instantiationService: IInstantiationService,
405-
@IThemeService themeService: IThemeService,
406-
@IContextMenuService contextMenuService: IContextMenuService,
407-
@IExtensionService extensionService: IExtensionService,
408-
@IWorkspaceContextService contextService: IWorkspaceContextService
409-
) {
410-
super(viewContainer.id, (instantiationService as any).createInstance(viewContainer.ctorDescriptor!.ctor, ...(viewContainer.ctorDescriptor!.staticArguments || [])), telemetryService, storageService, instantiationService, themeService, contextMenuService, extensionService, contextService);
411-
}
412-
}
413-
Registry.as<PanelRegistry>(PanelExtensions.Panels).registerPanel(PanelDescriptor.create(
414-
PaneContainerPanel,
415-
viewContainer.id,
416-
viewContainer.name,
417-
isString(viewContainer.icon) ? viewContainer.icon : undefined,
418-
viewContainer.order,
419-
viewContainer.focusCommand?.id,
420-
));
421-
};
422-
423-
const registerViewlet = (viewContainer: ViewContainer): void => {
424-
class PaneContainerViewlet extends Viewlet {
425-
constructor(
426-
@IConfigurationService configurationService: IConfigurationService,
427-
@IWorkbenchLayoutService layoutService: IWorkbenchLayoutService,
428-
@ITelemetryService telemetryService: ITelemetryService,
429-
@IWorkspaceContextService contextService: IWorkspaceContextService,
430-
@IStorageService storageService: IStorageService,
431-
@IEditorService editorService: IEditorService,
432-
@IInstantiationService instantiationService: IInstantiationService,
433-
@IThemeService themeService: IThemeService,
434-
@IContextMenuService contextMenuService: IContextMenuService,
435-
@IExtensionService extensionService: IExtensionService
436-
) {
437-
super(viewContainer.id, (instantiationService as any).createInstance(viewContainer.ctorDescriptor!.ctor, ...(viewContainer.ctorDescriptor!.staticArguments || [])), telemetryService, storageService, instantiationService, themeService, contextMenuService, extensionService, contextService, layoutService, configurationService);
438-
}
439-
}
440-
const viewletDescriptor = ViewletDescriptor.create(
441-
PaneContainerViewlet,
442-
viewContainer.id,
443-
viewContainer.name,
444-
isString(viewContainer.icon) ? viewContainer.icon : undefined,
445-
viewContainer.order,
446-
viewContainer.icon instanceof URI ? viewContainer.icon : undefined
447-
);
448-
449-
Registry.as<ViewletRegistry>(ViewletExtensions.Viewlets).registerViewlet(viewletDescriptor);
450-
};
451-
452-
const viewContainerRegistry = Registry.as<IViewContainersRegistry>(ViewContainerExtensions.ViewContainersRegistry);
453-
viewContainerRegistry.getViewContainers(ViewContainerLocation.Panel).forEach(viewContainer => registerPanel(viewContainer));
454-
viewContainerRegistry.onDidRegister(({ viewContainer, viewContainerLocation }) => {
455-
switch (viewContainerLocation) {
456-
case ViewContainerLocation.Panel:
457-
registerPanel(viewContainer);
458-
return;
459-
case ViewContainerLocation.Sidebar:
460-
if (viewContainer.ctorDescriptor) {
461-
registerViewlet(viewContainer);
462-
}
463-
return;
464-
}
465-
});
466-
})();

0 commit comments

Comments
 (0)