mirror of
https://github.com/microsoft/vscode.git
synced 2026-05-15 12:51:00 +01:00
Unify into single ViewContainerModel
This commit is contained in:
@@ -488,9 +488,9 @@ export class ResetViewLocationsAction extends Action {
|
||||
async run(): Promise<void> {
|
||||
const viewContainerRegistry = Registry.as<IViewContainersRegistry>(ViewContainerExtensions.ViewContainersRegistry);
|
||||
viewContainerRegistry.all.forEach(viewContainer => {
|
||||
const viewDescriptors = this.viewDescriptorService.getViewDescriptors(viewContainer);
|
||||
const viewContainerModel = this.viewDescriptorService.getViewContainerModel(viewContainer);
|
||||
|
||||
viewDescriptors.allViewDescriptors.forEach(viewDescriptor => {
|
||||
viewContainerModel.allViewDescriptors.forEach(viewDescriptor => {
|
||||
const defaultContainer = this.viewDescriptorService.getDefaultContainer(viewDescriptor.id);
|
||||
const currentContainer = this.viewDescriptorService.getViewContainer(viewDescriptor.id);
|
||||
|
||||
@@ -583,7 +583,7 @@ export class MoveFocusedViewAction extends Action {
|
||||
|
||||
const currentContainer = this.viewDescriptorService.getViewContainer(focusedViewId)!;
|
||||
const currentLocation = this.viewDescriptorService.getViewLocation(focusedViewId)!;
|
||||
const isViewSolo = this.viewDescriptorService.getViewDescriptors(currentContainer).allViewDescriptors.length === 1;
|
||||
const isViewSolo = this.viewDescriptorService.getViewContainerModel(currentContainer).allViewDescriptors.length === 1;
|
||||
|
||||
if (!(isViewSolo && currentLocation === ViewContainerLocation.Sidebar)) {
|
||||
items.push({
|
||||
|
||||
@@ -26,7 +26,7 @@ import { IExtensionService } from 'vs/workbench/services/extensions/common/exten
|
||||
import { URI, UriComponents } from 'vs/base/common/uri';
|
||||
import { ToggleCompositePinnedAction, ICompositeBarColors, ActivityAction, ICompositeActivity } from 'vs/workbench/browser/parts/compositeBarActions';
|
||||
import { ViewletDescriptor } from 'vs/workbench/browser/viewlet';
|
||||
import { IViewDescriptorService, IViewContainersRegistry, Extensions as ViewContainerExtensions, ViewContainer, TEST_VIEW_CONTAINER_ID, IViewDescriptorCollection, ViewContainerLocation } from 'vs/workbench/common/views';
|
||||
import { IViewDescriptorService, IViewContainersRegistry, Extensions as ViewContainerExtensions, ViewContainer, TEST_VIEW_CONTAINER_ID, IViewContainerModel, ViewContainerLocation } from 'vs/workbench/common/views';
|
||||
import { IContextKeyService, ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { IViewlet } from 'vs/workbench/common/viewlet';
|
||||
import { isUndefinedOrNull, assertIsDefined, isString } from 'vs/base/common/types';
|
||||
@@ -218,8 +218,8 @@ export class ActivitybarPart extends Part implements IActivityBarService {
|
||||
if (viewletDescriptor) {
|
||||
const viewContainer = this.getViewContainer(viewletDescriptor.id);
|
||||
if (viewContainer?.hideIfEmpty) {
|
||||
const viewDescriptors = this.viewDescriptorService.getViewDescriptors(viewContainer);
|
||||
if (viewDescriptors.activeViewDescriptors.length === 0) {
|
||||
const viewContainerModel = this.viewDescriptorService.getViewContainerModel(viewContainer);
|
||||
if (viewContainerModel.activeViewDescriptors.length === 0) {
|
||||
this.hideComposite(viewletDescriptor.id); // Update the composite bar by hiding
|
||||
}
|
||||
}
|
||||
@@ -490,13 +490,12 @@ export class ActivitybarPart extends Part implements IActivityBarService {
|
||||
for (const viewlet of viewlets) {
|
||||
this.enableCompositeActions(viewlet);
|
||||
const viewContainer = this.getViewContainer(viewlet.id)!;
|
||||
const viewDescriptors = this.viewDescriptorService.getViewDescriptors(viewContainer);
|
||||
this.onDidChangeActiveViews(viewlet, viewDescriptors, viewContainer.hideIfEmpty);
|
||||
const viewContainerModel = this.viewDescriptorService.getViewContainerModel(viewContainer);
|
||||
this.onDidChangeActiveViews(viewlet, viewContainerModel, viewContainer.hideIfEmpty);
|
||||
|
||||
const disposables = new DisposableStore();
|
||||
disposables.add(viewDescriptors.onDidChangeActiveViews(() => this.onDidChangeActiveViews(viewlet, viewDescriptors, viewContainer.hideIfEmpty)));
|
||||
disposables.add(viewDescriptors.onDidChangeViews(() => this.onDidUpdateViews(viewlet, viewDescriptors)));
|
||||
disposables.add(viewDescriptors.onDidMove(() => this.onDidUpdateViews(viewlet, viewDescriptors)));
|
||||
disposables.add(viewContainerModel.onDidChangeActiveViewDescriptors(() => this.onDidChangeActiveViews(viewlet, viewContainerModel, viewContainer.hideIfEmpty)));
|
||||
disposables.add(viewContainerModel.onDidChangeContainerInfo(() => this.updateActivity(viewlet, viewContainerModel)));
|
||||
|
||||
this.viewletDisposables.set(viewlet.id, disposables);
|
||||
}
|
||||
@@ -512,12 +511,12 @@ export class ActivitybarPart extends Part implements IActivityBarService {
|
||||
this.hideComposite(viewletId);
|
||||
}
|
||||
|
||||
private updateActivity(viewlet: ViewletDescriptor, viewDescriptors: IViewDescriptorCollection): void {
|
||||
const icon = viewDescriptors.getIcon();
|
||||
private updateActivity(viewlet: ViewletDescriptor, viewContainerModel: IViewContainerModel): void {
|
||||
const icon = viewContainerModel.icon;
|
||||
|
||||
const activity: IActivity = {
|
||||
id: viewlet.id,
|
||||
name: viewDescriptors.getTitle(),
|
||||
name: viewContainerModel.title,
|
||||
cssClass: isString(icon) ? icon : undefined,
|
||||
iconUrl: icon instanceof URI ? icon : undefined,
|
||||
keybindingId: viewlet.keybindingId
|
||||
@@ -531,11 +530,7 @@ export class ActivitybarPart extends Part implements IActivityBarService {
|
||||
}
|
||||
}
|
||||
|
||||
private onDidUpdateViews(viewlet: ViewletDescriptor, viewDescriptors: IViewDescriptorCollection): void {
|
||||
this.updateActivity(viewlet, viewDescriptors);
|
||||
}
|
||||
|
||||
private onDidChangeActiveViews(viewlet: ViewletDescriptor, viewDescriptors: IViewDescriptorCollection, hideIfEmpty?: boolean): void {
|
||||
private onDidChangeActiveViews(viewlet: ViewletDescriptor, viewDescriptors: IViewContainerModel, hideIfEmpty?: boolean): void {
|
||||
if (viewDescriptors.activeViewDescriptors.length) {
|
||||
this.updateActivity(viewlet, viewDescriptors);
|
||||
this.compositeBar.addComposite(viewlet);
|
||||
@@ -663,8 +658,8 @@ export class ActivitybarPart extends Part implements IActivityBarService {
|
||||
if (viewlet) {
|
||||
const views: { when: string | undefined }[] = [];
|
||||
if (viewContainer) {
|
||||
const viewDescriptors = this.viewDescriptorService.getViewDescriptors(viewContainer);
|
||||
for (const { when } of viewDescriptors.allViewDescriptors) {
|
||||
const viewContainerModel = this.viewDescriptorService.getViewContainerModel(viewContainer);
|
||||
for (const { when } of viewContainerModel.allViewDescriptors) {
|
||||
views.push({ when: when ? when.serialize() : undefined });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,7 +56,7 @@ export class CompositeDragAndDrop implements ICompositeDragAndDrop {
|
||||
}
|
||||
// ... on a different composite bar
|
||||
else {
|
||||
const viewsToMove = this.viewDescriptorService.getViewDescriptors(currentContainer)!.allViewDescriptors;
|
||||
const viewsToMove = this.viewDescriptorService.getViewContainerModel(currentContainer)!.allViewDescriptors;
|
||||
if (viewsToMove.some(v => !v.canMoveView)) {
|
||||
return;
|
||||
}
|
||||
@@ -119,7 +119,7 @@ export class CompositeDragAndDrop implements ICompositeDragAndDrop {
|
||||
}
|
||||
|
||||
// ... to another composite location
|
||||
const draggedViews = this.viewDescriptorService.getViewDescriptors(currentContainer)!.allViewDescriptors;
|
||||
const draggedViews = this.viewDescriptorService.getViewContainerModel(currentContainer)!.allViewDescriptors;
|
||||
|
||||
// ... all views must be movable
|
||||
return !draggedViews.some(v => !v.canMoveView);
|
||||
|
||||
@@ -33,7 +33,7 @@ import { IContextKey, IContextKeyService, ContextKeyExpr } from 'vs/platform/con
|
||||
import { isUndefinedOrNull, assertIsDefined } from 'vs/base/common/types';
|
||||
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
|
||||
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { ViewContainer, IViewContainersRegistry, Extensions as ViewContainerExtensions, IViewDescriptorService, IViewDescriptorCollection, ViewContainerLocation } from 'vs/workbench/common/views';
|
||||
import { ViewContainer, IViewContainersRegistry, Extensions as ViewContainerExtensions, IViewDescriptorService, IViewContainerModel, ViewContainerLocation } from 'vs/workbench/common/views';
|
||||
import { MenuId } from 'vs/platform/actions/common/actions';
|
||||
import { ViewMenuActions } from 'vs/workbench/browser/parts/views/viewMenuActions';
|
||||
import { IPaneComposite } from 'vs/workbench/common/panecomposite';
|
||||
@@ -178,9 +178,9 @@ export class PanelPart extends CompositePart<Panel> implements IPanelService {
|
||||
const result: IAction[] = [];
|
||||
const container = this.getViewContainer(compositeId);
|
||||
if (container) {
|
||||
const viewDescriptors = this.viewDescriptorService.getViewDescriptors(container);
|
||||
if (viewDescriptors.allViewDescriptors.length === 1) {
|
||||
const viewMenuActions = this.instantiationService.createInstance(ViewMenuActions, viewDescriptors.allViewDescriptors[0].id, MenuId.ViewTitle, MenuId.ViewTitleContext);
|
||||
const viewContainerModel = this.viewDescriptorService.getViewContainerModel(container);
|
||||
if (viewContainerModel.allViewDescriptors.length === 1) {
|
||||
const viewMenuActions = this.instantiationService.createInstance(ViewMenuActions, viewContainerModel.allViewDescriptors[0].id, MenuId.ViewTitle, MenuId.ViewTitleContext);
|
||||
result.push(...viewMenuActions.getContextMenuActions());
|
||||
viewMenuActions.dispose();
|
||||
}
|
||||
@@ -211,13 +211,13 @@ export class PanelPart extends CompositePart<Panel> implements IPanelService {
|
||||
for (const panel of panels) {
|
||||
this.enableCompositeActions(panel);
|
||||
const viewContainer = this.getViewContainer(panel.id)!;
|
||||
const viewDescriptors = this.viewDescriptorService.getViewDescriptors(viewContainer);
|
||||
this.onDidChangeActiveViews(panel, viewDescriptors, viewContainer.hideIfEmpty);
|
||||
const viewContainerModel = this.viewDescriptorService.getViewContainerModel(viewContainer);
|
||||
this.onDidChangeActiveViews(panel, viewContainerModel, viewContainer.hideIfEmpty);
|
||||
|
||||
const disposables = new DisposableStore();
|
||||
disposables.add(viewDescriptors.onDidChangeActiveViews(() => this.onDidChangeActiveViews(panel, viewDescriptors, viewContainer.hideIfEmpty)));
|
||||
disposables.add(viewDescriptors.onDidChangeViews(() => this.onDidUpdateViews(panel, viewDescriptors)));
|
||||
disposables.add(viewDescriptors.onDidMove(() => this.onDidUpdateViews(panel, viewDescriptors)));
|
||||
disposables.add(viewContainerModel.onDidChangeActiveViewDescriptors(() => this.onDidChangeActiveViews(panel, viewContainerModel, viewContainer.hideIfEmpty)));
|
||||
disposables.add(viewContainerModel.onDidChangeAllViewDescriptors(() => this.onDidUpdateViews(panel, viewContainerModel)));
|
||||
disposables.add(viewContainerModel.onDidMoveVisibleViewDescriptors(() => this.onDidUpdateViews(panel, viewContainerModel)));
|
||||
|
||||
this.panelDisposables.set(panel.id, disposables);
|
||||
}
|
||||
@@ -242,10 +242,10 @@ export class PanelPart extends CompositePart<Panel> implements IPanelService {
|
||||
}
|
||||
}
|
||||
|
||||
private updateActivity(panel: PanelDescriptor, viewDescriptors: IViewDescriptorCollection): void {
|
||||
private updateActivity(panel: PanelDescriptor, viewContainerModel: IViewContainerModel): void {
|
||||
const activity: IActivity = {
|
||||
id: panel.id,
|
||||
name: viewDescriptors.getTitle(),
|
||||
name: viewContainerModel.title,
|
||||
keybindingId: panel.keybindingId
|
||||
};
|
||||
|
||||
@@ -257,11 +257,11 @@ export class PanelPart extends CompositePart<Panel> implements IPanelService {
|
||||
}
|
||||
}
|
||||
|
||||
private onDidUpdateViews(panel: PanelDescriptor, viewDescriptors: IViewDescriptorCollection): void {
|
||||
private onDidUpdateViews(panel: PanelDescriptor, viewDescriptors: IViewContainerModel): void {
|
||||
this.updateActivity(panel, viewDescriptors);
|
||||
}
|
||||
|
||||
private onDidChangeActiveViews(panel: PanelDescriptor, viewDescriptors: IViewDescriptorCollection, hideIfEmpty?: boolean): void {
|
||||
private onDidChangeActiveViews(panel: PanelDescriptor, viewDescriptors: IViewContainerModel, hideIfEmpty?: boolean): void {
|
||||
if (viewDescriptors.activeViewDescriptors.length) {
|
||||
this.updateActivity(panel, viewDescriptors);
|
||||
this.compositeBar.addComposite(panel);
|
||||
@@ -343,8 +343,8 @@ export class PanelPart extends CompositePart<Panel> implements IPanelService {
|
||||
if (panelDescriptor) {
|
||||
const viewContainer = this.getViewContainer(panelDescriptor.id);
|
||||
if (viewContainer?.hideIfEmpty) {
|
||||
const viewDescriptors = this.viewDescriptorService.getViewDescriptors(viewContainer);
|
||||
if (viewDescriptors.activeViewDescriptors.length === 0 && this.compositeBar.getPinnedComposites().length > 1) {
|
||||
const viewContainerModel = this.viewDescriptorService.getViewContainerModel(viewContainer);
|
||||
if (viewContainerModel.activeViewDescriptors.length === 0 && this.compositeBar.getPinnedComposites().length > 1) {
|
||||
this.hideComposite(panelDescriptor.id); // Update the composite bar by hiding
|
||||
}
|
||||
}
|
||||
@@ -610,10 +610,11 @@ export class PanelPart extends CompositePart<Panel> implements IPanelService {
|
||||
|
||||
const compositeItems = this.compositeBar.getCompositeBarItems();
|
||||
for (const compositeItem of compositeItems) {
|
||||
const viewContainer = this.getViewContainer(compositeItem.id)!;
|
||||
const viewDescriptors = this.viewDescriptorService.getViewDescriptors(viewContainer);
|
||||
|
||||
state.push({ id: compositeItem.id, name: viewDescriptors.getTitle(), pinned: compositeItem.pinned, order: compositeItem.order, visible: compositeItem.visible });
|
||||
const viewContainer = this.getViewContainer(compositeItem.id);
|
||||
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 });
|
||||
}
|
||||
}
|
||||
|
||||
this.cachedPanelsValue = JSON.stringify(state);
|
||||
|
||||
@@ -24,7 +24,7 @@ import { PaneView, IPaneViewOptions, IPaneOptions, Pane } from 'vs/base/browser/
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { IWorkbenchLayoutService, Position } from 'vs/workbench/services/layout/browser/layoutService';
|
||||
import { StandardMouseEvent } from 'vs/base/browser/mouseEvent';
|
||||
import { Extensions as ViewContainerExtensions, IView, FocusedViewContext, IViewContainersRegistry, IViewDescriptor, ViewContainer, IViewDescriptorService, ViewContainerLocation, IViewPaneContainer, IViewsRegistry, IViewContentDescriptor, IAddedViewDescriptorRef, IViewDescriptorRef, IViewDescriptorCollection } from 'vs/workbench/common/views';
|
||||
import { Extensions as ViewContainerExtensions, IView, FocusedViewContext, IViewContainersRegistry, IViewDescriptor, ViewContainer, IViewDescriptorService, ViewContainerLocation, IViewPaneContainer, IViewsRegistry, IViewContentDescriptor, IAddedViewDescriptorRef, IViewDescriptorRef, IViewContainerModel } from 'vs/workbench/common/views';
|
||||
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
|
||||
import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { assertIsDefined } from 'vs/base/common/types';
|
||||
@@ -745,7 +745,7 @@ export class ViewPaneContainer extends Component implements IViewPaneContainer {
|
||||
|
||||
private readonly visibleViewsCountFromCache: number | undefined;
|
||||
private readonly visibleViewsStorageId: string;
|
||||
protected readonly viewsDescriptors: IViewDescriptorCollection;
|
||||
protected readonly viewContainerModel: IViewContainerModel;
|
||||
private viewDisposables: IDisposable[] = [];
|
||||
|
||||
private readonly _onTitleAreaUpdate: Emitter<void> = this._register(new Emitter<void>());
|
||||
@@ -806,7 +806,7 @@ export class ViewPaneContainer extends Component implements IViewPaneContainer {
|
||||
this.visibleViewsStorageId = `${id}.numberOfVisibleViews`;
|
||||
this.visibleViewsCountFromCache = this.storageService.getNumber(this.visibleViewsStorageId, StorageScope.WORKSPACE, undefined);
|
||||
this._register(toDisposable(() => this.viewDisposables = dispose(this.viewDisposables)));
|
||||
this.viewsDescriptors = this.viewDescriptorService.getViewDescriptors(container);
|
||||
this.viewContainerModel = this.viewDescriptorService.getViewContainerModel(container);
|
||||
}
|
||||
|
||||
create(parent: HTMLElement): void {
|
||||
@@ -837,7 +837,7 @@ export class ViewPaneContainer extends Component implements IViewPaneContainer {
|
||||
const viewContainerRegistry = Registry.as<IViewContainersRegistry>(ViewContainerExtensions.ViewContainersRegistry);
|
||||
|
||||
const container = viewContainerRegistry.get(dropData.id)!;
|
||||
const viewsToMove = this.viewDescriptorService.getViewDescriptors(container).allViewDescriptors;
|
||||
const viewsToMove = this.viewDescriptorService.getViewContainerModel(container).allViewDescriptors;
|
||||
|
||||
if (!viewsToMove.some(v => !v.canMoveView)) {
|
||||
overlay = new ViewPaneDropOverlay(parent, undefined, this.themeService);
|
||||
@@ -859,7 +859,7 @@ export class ViewPaneContainer extends Component implements IViewPaneContainer {
|
||||
const viewContainerRegistry = Registry.as<IViewContainersRegistry>(ViewContainerExtensions.ViewContainersRegistry);
|
||||
|
||||
const container = viewContainerRegistry.get(dropData.id)!;
|
||||
const allViews = this.viewDescriptorService.getViewDescriptors(container).allViewDescriptors;
|
||||
const allViews = this.viewDescriptorService.getViewContainerModel(container).allViewDescriptors;
|
||||
if (!allViews.some(v => !v.canMoveView)) {
|
||||
viewsToMove.push(...allViews);
|
||||
}
|
||||
@@ -882,11 +882,11 @@ export class ViewPaneContainer extends Component implements IViewPaneContainer {
|
||||
}));
|
||||
|
||||
this._register(this.onDidSashChange(() => this.saveViewSizes()));
|
||||
this.viewsDescriptors.onDidAdd(added => this.onDidAddViewDescriptors(added));
|
||||
this.viewsDescriptors.onDidRemove(removed => this.onDidRemoveViewDescriptors(removed));
|
||||
const addedViews: IAddedViewDescriptorRef[] = this.viewsDescriptors.visibleViewDescriptors.map((viewDescriptor, index) => {
|
||||
const size = this.viewsDescriptors.getSize(viewDescriptor.id);
|
||||
const collapsed = this.viewsDescriptors.isCollapsed(viewDescriptor.id);
|
||||
this.viewContainerModel.onDidAddVisibleViewDescriptors(added => this.onDidAddViewDescriptors(added));
|
||||
this.viewContainerModel.onDidRemoveVisibleViewDescriptors(removed => this.onDidRemoveViewDescriptors(removed));
|
||||
const addedViews: IAddedViewDescriptorRef[] = this.viewContainerModel.visibleViewDescriptors.map((viewDescriptor, index) => {
|
||||
const size = this.viewContainerModel.getSize(viewDescriptor.id);
|
||||
const collapsed = this.viewContainerModel.isCollapsed(viewDescriptor.id);
|
||||
return ({ viewDescriptor, index, size, collapsed });
|
||||
});
|
||||
if (addedViews.length) {
|
||||
@@ -904,7 +904,7 @@ export class ViewPaneContainer extends Component implements IViewPaneContainer {
|
||||
}
|
||||
|
||||
getTitle(): string {
|
||||
const containerTitle = this.viewsDescriptors.getTitle();
|
||||
const containerTitle = this.viewContainerModel.title;
|
||||
|
||||
if (this.isViewMergedWithContainer()) {
|
||||
const paneItemTitle = this.paneItems[0].pane.title;
|
||||
@@ -955,10 +955,10 @@ export class ViewPaneContainer extends Component implements IViewPaneContainer {
|
||||
}
|
||||
}
|
||||
|
||||
const viewToggleActions = this.viewsDescriptors.activeViewDescriptors.map(viewDescriptor => (<IAction>{
|
||||
const viewToggleActions = this.viewContainerModel.activeViewDescriptors.map(viewDescriptor => (<IAction>{
|
||||
id: `${viewDescriptor.id}.toggleVisibility`,
|
||||
label: viewDescriptor.name,
|
||||
checked: this.viewsDescriptors.isVisible(viewDescriptor.id),
|
||||
checked: this.viewContainerModel.isVisible(viewDescriptor.id),
|
||||
enabled: viewDescriptor.canToggleVisibility,
|
||||
run: () => this.toggleViewVisibility(viewDescriptor.id)
|
||||
}));
|
||||
@@ -1087,7 +1087,7 @@ export class ViewPaneContainer extends Component implements IViewPaneContainer {
|
||||
// Save size only when the layout has happened
|
||||
if (this.didLayout) {
|
||||
for (const view of this.panes) {
|
||||
this.viewsDescriptors.setSize(view.id, this.getPaneSize(view));
|
||||
this.viewContainerModel.setSize(view.id, this.getPaneSize(view));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1096,10 +1096,10 @@ export class ViewPaneContainer extends Component implements IViewPaneContainer {
|
||||
// Restore sizes only when the layout has happened
|
||||
if (this.didLayout) {
|
||||
let initialSizes;
|
||||
for (let i = 0; i < this.viewsDescriptors.visibleViewDescriptors.length; i++) {
|
||||
for (let i = 0; i < this.viewContainerModel.visibleViewDescriptors.length; i++) {
|
||||
const pane = this.panes[i];
|
||||
const viewDescriptor = this.viewsDescriptors.visibleViewDescriptors[i];
|
||||
const size = this.viewsDescriptors.getSize(viewDescriptor.id);
|
||||
const viewDescriptor = this.viewContainerModel.visibleViewDescriptors[i];
|
||||
const size = this.viewContainerModel.getSize(viewDescriptor.id);
|
||||
|
||||
if (typeof size === 'number') {
|
||||
this.resizePane(pane, size);
|
||||
@@ -1114,8 +1114,8 @@ export class ViewPaneContainer extends Component implements IViewPaneContainer {
|
||||
private computeInitialSizes(): Map<string, number> {
|
||||
const sizes: Map<string, number> = new Map<string, number>();
|
||||
if (this.dimension) {
|
||||
const totalWeight = this.viewsDescriptors.visibleViewDescriptors.reduce((totalWeight, { weight }) => totalWeight + (weight || 20), 0);
|
||||
for (const viewDescriptor of this.viewsDescriptors.visibleViewDescriptors) {
|
||||
const totalWeight = this.viewContainerModel.visibleViewDescriptors.reduce((totalWeight, { weight }) => totalWeight + (weight || 20), 0);
|
||||
for (const viewDescriptor of this.viewContainerModel.visibleViewDescriptors) {
|
||||
if (this.orientation === Orientation.VERTICAL) {
|
||||
sizes.set(viewDescriptor.id, this.dimension.height * (viewDescriptor.weight || 20) / totalWeight);
|
||||
} else {
|
||||
@@ -1176,7 +1176,7 @@ export class ViewPaneContainer extends Component implements IViewPaneContainer {
|
||||
});
|
||||
|
||||
const collapseDisposable = Event.latch(Event.map(pane.onDidChange, () => !pane.isExpanded()))(collapsed => {
|
||||
this.viewsDescriptors.setCollapsed(viewDescriptor.id, collapsed);
|
||||
this.viewContainerModel.setCollapsed(viewDescriptor.id, collapsed);
|
||||
});
|
||||
|
||||
this.viewDisposables.splice(index, 0, combinedDisposable(contextMenuDisposable, collapseDisposable));
|
||||
@@ -1207,13 +1207,13 @@ export class ViewPaneContainer extends Component implements IViewPaneContainer {
|
||||
}
|
||||
|
||||
protected toggleViewVisibility(viewId: string): void {
|
||||
const visible = !this.viewsDescriptors.isVisible(viewId);
|
||||
const visible = !this.viewContainerModel.isVisible(viewId);
|
||||
type ViewsToggleVisibilityClassification = {
|
||||
viewId: { classification: 'SystemMetaData', purpose: 'FeatureInsight' };
|
||||
visible: { classification: 'SystemMetaData', purpose: 'FeatureInsight' };
|
||||
};
|
||||
this.telemetryService.publicLog2<{ viewId: String, visible: boolean }, ViewsToggleVisibilityClassification>('views.toggleVisibility', { viewId, visible });
|
||||
this.viewsDescriptors.setVisible(viewId, visible);
|
||||
this.viewContainerModel.setVisible(viewId, visible);
|
||||
}
|
||||
|
||||
private addPane(pane: ViewPane, size: number, index = this.paneItems.length - 1): void {
|
||||
@@ -1268,7 +1268,7 @@ export class ViewPaneContainer extends Component implements IViewPaneContainer {
|
||||
const viewContainerRegistry = Registry.as<IViewContainersRegistry>(ViewContainerExtensions.ViewContainersRegistry);
|
||||
|
||||
const container = viewContainerRegistry.get(dropData.id)!;
|
||||
const viewsToMove = this.viewDescriptorService.getViewDescriptors(container).allViewDescriptors;
|
||||
const viewsToMove = this.viewDescriptorService.getViewContainerModel(container).allViewDescriptors;
|
||||
|
||||
if (!viewsToMove.some(v => !v.canMoveView)) {
|
||||
overlay = new ViewPaneDropOverlay(pane.dropTargetElement, this.orientation ?? Orientation.VERTICAL, this.themeService);
|
||||
@@ -1290,7 +1290,7 @@ export class ViewPaneContainer extends Component implements IViewPaneContainer {
|
||||
const viewContainerRegistry = Registry.as<IViewContainersRegistry>(ViewContainerExtensions.ViewContainersRegistry);
|
||||
|
||||
const container = viewContainerRegistry.get(dropData.id)!;
|
||||
const allViews = this.viewDescriptorService.getViewDescriptors(container).allViewDescriptors;
|
||||
const allViews = this.viewDescriptorService.getViewContainerModel(container).allViewDescriptors;
|
||||
|
||||
if (allViews.length > 0 && !allViews.some(v => !v.canMoveView)) {
|
||||
viewsToMove.push(...allViews);
|
||||
@@ -1405,8 +1405,8 @@ export class ViewPaneContainer extends Component implements IViewPaneContainer {
|
||||
const fromIndex = firstIndex(this.paneItems, item => item.pane === from);
|
||||
const toIndex = firstIndex(this.paneItems, item => item.pane === to);
|
||||
|
||||
const fromViewDescriptor = this.viewsDescriptors.visibleViewDescriptors[fromIndex];
|
||||
const toViewDescriptor = this.viewsDescriptors.visibleViewDescriptors[toIndex];
|
||||
const fromViewDescriptor = this.viewContainerModel.visibleViewDescriptors[fromIndex];
|
||||
const toViewDescriptor = this.viewContainerModel.visibleViewDescriptors[toIndex];
|
||||
|
||||
if (fromIndex < 0 || fromIndex >= this.paneItems.length) {
|
||||
return;
|
||||
@@ -1421,7 +1421,7 @@ export class ViewPaneContainer extends Component implements IViewPaneContainer {
|
||||
|
||||
assertIsDefined(this.paneview).movePane(from, to);
|
||||
|
||||
this.viewsDescriptors.move(fromViewDescriptor.id, toViewDescriptor.id);
|
||||
this.viewContainerModel.move(fromViewDescriptor.id, toViewDescriptor.id);
|
||||
|
||||
this.updateTitleArea();
|
||||
}
|
||||
|
||||
@@ -109,15 +109,15 @@ export class ViewsService extends Disposable implements IViewsService {
|
||||
|
||||
private onDidRegisterViewContainer(viewContainer: ViewContainer, viewContainerLocation: ViewContainerLocation): void {
|
||||
this.registerViewletOrPanel(viewContainer, viewContainerLocation);
|
||||
const viewDescriptorCollection = this.viewDescriptorService.getViewDescriptors(viewContainer);
|
||||
this.onViewDescriptorsAdded(viewDescriptorCollection.allViewDescriptors, viewContainer);
|
||||
this._register(viewDescriptorCollection.onDidChangeViews(({ added, removed }) => {
|
||||
const viewContainerModel = this.viewDescriptorService.getViewContainerModel(viewContainer);
|
||||
this.onViewDescriptorsAdded(viewContainerModel.allViewDescriptors, viewContainer);
|
||||
this._register(viewContainerModel.onDidChangeAllViewDescriptors(({ added, removed }) => {
|
||||
this.onViewDescriptorsAdded(added, viewContainer);
|
||||
this.onViewDescriptorsRemoved(removed);
|
||||
}));
|
||||
}
|
||||
|
||||
private onViewDescriptorsAdded(views: IViewDescriptor[], container: ViewContainer): void {
|
||||
private onViewDescriptorsAdded(views: ReadonlyArray<IViewDescriptor>, container: ViewContainer): void {
|
||||
const location = this.viewContainersRegistry.getViewContainerLocation(container);
|
||||
if (location === undefined) {
|
||||
return;
|
||||
@@ -181,7 +181,7 @@ export class ViewsService extends Disposable implements IViewsService {
|
||||
}
|
||||
}
|
||||
|
||||
private onViewDescriptorsRemoved(views: IViewDescriptor[]): void {
|
||||
private onViewDescriptorsRemoved(views: ReadonlyArray<IViewDescriptor>): void {
|
||||
for (const view of views) {
|
||||
const disposable = this.viewDisposable.get(view);
|
||||
if (disposable) {
|
||||
|
||||
@@ -46,8 +46,8 @@ export abstract class FilterViewPaneContainer extends ViewPaneContainer {
|
||||
this.onFilterChanged(newFilterValue);
|
||||
}));
|
||||
|
||||
this._register(this.viewsDescriptors.onDidChangeActiveViews((viewDescriptors) => {
|
||||
this.updateAllViews(viewDescriptors);
|
||||
this._register(this.viewContainerModel.onDidChangeActiveViewDescriptors(() => {
|
||||
this.updateAllViews(this.viewContainerModel.activeViewDescriptors);
|
||||
}));
|
||||
}
|
||||
|
||||
@@ -62,7 +62,7 @@ export abstract class FilterViewPaneContainer extends ViewPaneContainer {
|
||||
}
|
||||
this.allViews.get(filterOnValue)!.set(descriptor.id, descriptor);
|
||||
if (this.filterValue && !this.filterValue.includes(filterOnValue)) {
|
||||
this.viewsDescriptors.setVisible(descriptor.id, false);
|
||||
this.viewContainerModel.setVisible(descriptor.id, false);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -75,17 +75,17 @@ export abstract class FilterViewPaneContainer extends ViewPaneContainer {
|
||||
|
||||
private onFilterChanged(newFilterValue: string[]) {
|
||||
if (this.allViews.size === 0) {
|
||||
this.updateAllViews(this.viewsDescriptors.activeViewDescriptors);
|
||||
this.updateAllViews(this.viewContainerModel.activeViewDescriptors);
|
||||
}
|
||||
this.getViewsNotForTarget(newFilterValue).forEach(item => this.viewsDescriptors.setVisible(item.id, false));
|
||||
this.getViewsForTarget(newFilterValue).forEach(item => this.viewsDescriptors.setVisible(item.id, true));
|
||||
this.getViewsNotForTarget(newFilterValue).forEach(item => this.viewContainerModel.setVisible(item.id, false));
|
||||
this.getViewsForTarget(newFilterValue).forEach(item => this.viewContainerModel.setVisible(item.id, true));
|
||||
}
|
||||
|
||||
getContextMenuActions(): IAction[] {
|
||||
const result: IAction[] = Array.from(this.constantViewDescriptors.values()).map(viewDescriptor => (<IAction>{
|
||||
id: `${viewDescriptor.id}.toggleVisibility`,
|
||||
label: viewDescriptor.name,
|
||||
checked: this.viewsDescriptors.isVisible(viewDescriptor.id),
|
||||
checked: this.viewContainerModel.isVisible(viewDescriptor.id),
|
||||
enabled: viewDescriptor.canToggleVisibility,
|
||||
run: () => this.toggleViewVisibility(viewDescriptor.id)
|
||||
}));
|
||||
@@ -133,7 +133,7 @@ export abstract class FilterViewPaneContainer extends ViewPaneContainer {
|
||||
}
|
||||
// Check that allViews is ready
|
||||
if (this.allViews.size === 0) {
|
||||
this.updateAllViews(this.viewsDescriptors.activeViewDescriptors);
|
||||
this.updateAllViews(this.viewContainerModel.activeViewDescriptors);
|
||||
}
|
||||
return panes;
|
||||
}
|
||||
|
||||
@@ -219,18 +219,22 @@ export interface IAddedViewDescriptorRef extends IViewDescriptorRef {
|
||||
size?: number;
|
||||
}
|
||||
|
||||
export interface IViewDescriptorCollection extends IDisposable {
|
||||
export interface IViewContainerModel {
|
||||
|
||||
readonly allViewDescriptors: IViewDescriptor[];
|
||||
readonly onDidChangeViews: Event<{ added: IViewDescriptor[], removed: IViewDescriptor[] }>;
|
||||
readonly title: string;
|
||||
readonly icon: string | URI | undefined;
|
||||
readonly onDidChangeContainerInfo: Event<{ title?: boolean, icon?: boolean }>;
|
||||
|
||||
readonly activeViewDescriptors: IViewDescriptor[];
|
||||
readonly onDidChangeActiveViews: Event<ReadonlyArray<IViewDescriptor>>;
|
||||
readonly allViewDescriptors: ReadonlyArray<IViewDescriptor>;
|
||||
readonly onDidChangeAllViewDescriptors: Event<{ added: ReadonlyArray<IViewDescriptor>, removed: ReadonlyArray<IViewDescriptor> }>;
|
||||
|
||||
readonly visibleViewDescriptors: IViewDescriptor[];
|
||||
readonly onDidAdd: Event<IAddedViewDescriptorRef[]>;
|
||||
readonly onDidRemove: Event<IViewDescriptorRef[]>
|
||||
readonly onDidMove: Event<{ from: IViewDescriptorRef; to: IViewDescriptorRef; }>
|
||||
readonly activeViewDescriptors: ReadonlyArray<IViewDescriptor>;
|
||||
readonly onDidChangeActiveViewDescriptors: Event<{ added: ReadonlyArray<IViewDescriptor>, removed: ReadonlyArray<IViewDescriptor> }>;
|
||||
|
||||
readonly visibleViewDescriptors: ReadonlyArray<IViewDescriptor>;
|
||||
readonly onDidAddVisibleViewDescriptors: Event<IAddedViewDescriptorRef[]>;
|
||||
readonly onDidRemoveVisibleViewDescriptors: Event<IViewDescriptorRef[]>
|
||||
readonly onDidMoveVisibleViewDescriptors: Event<{ from: IViewDescriptorRef; to: IViewDescriptorRef; }>
|
||||
|
||||
isVisible(id: string): boolean;
|
||||
setVisible(id: string, visible: boolean, size?: number): void;
|
||||
@@ -241,9 +245,6 @@ export interface IViewDescriptorCollection extends IDisposable {
|
||||
getSize(id: string): number | undefined;
|
||||
setSize(id: string, size: number): void
|
||||
|
||||
getTitle(): string;
|
||||
getIcon(): URI | string | undefined;
|
||||
|
||||
move(from: string, to: string): void;
|
||||
}
|
||||
|
||||
@@ -484,7 +485,7 @@ export interface IViewDescriptorService {
|
||||
|
||||
moveViewsToContainer(views: IViewDescriptor[], viewContainer: ViewContainer): void;
|
||||
|
||||
getViewDescriptors(container: ViewContainer): IViewDescriptorCollection;
|
||||
getViewContainerModel(container: ViewContainer): IViewContainerModel;
|
||||
|
||||
getViewDescriptor(viewId: string): IViewDescriptor | null;
|
||||
|
||||
|
||||
@@ -96,9 +96,9 @@ export class ViewQuickAccessProvider extends PickerQuickAccessProvider<IViewQuic
|
||||
const viewEntries: Array<IViewQuickPickItem> = [];
|
||||
|
||||
const getViewEntriesForViewlet = (viewlet: ViewletDescriptor, viewContainer: ViewContainer): IViewQuickPickItem[] => {
|
||||
const viewDescriptors = this.viewDescriptorService.getViewDescriptors(viewContainer);
|
||||
const viewContainerModel = this.viewDescriptorService.getViewContainerModel(viewContainer);
|
||||
const result: IViewQuickPickItem[] = [];
|
||||
for (const view of viewDescriptors.allViewDescriptors) {
|
||||
for (const view of viewContainerModel.allViewDescriptors) {
|
||||
if (this.contextKeyService.contextMatchesRules(view.when)) {
|
||||
result.push({
|
||||
label: view.name,
|
||||
@@ -176,7 +176,7 @@ export class ViewQuickAccessProvider extends PickerQuickAccessProvider<IViewQuic
|
||||
private includeViewContainer(container: ViewletDescriptor | IPanelIdentifier): boolean {
|
||||
const viewContainer = Registry.as<IViewContainersRegistry>(ViewExtensions.ViewContainersRegistry).get(container.id);
|
||||
if (viewContainer?.hideIfEmpty) {
|
||||
return this.viewDescriptorService.getViewDescriptors(viewContainer).activeViewDescriptors.length > 0;
|
||||
return this.viewDescriptorService.getViewContainerModel(viewContainer).activeViewDescriptors.length > 0;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
@@ -101,7 +101,7 @@ export class SCMViewPaneContainer extends ViewPaneContainer implements IViewMode
|
||||
}
|
||||
|
||||
get onDidChangeVisibleRepositories(): Event<ISCMRepository[]> {
|
||||
const modificationEvent = Event.debounce(Event.any(this.viewsDescriptors.onDidAdd, this.viewsDescriptors.onDidRemove), () => null, 0);
|
||||
const modificationEvent = Event.debounce(Event.any(this.viewContainerModel.onDidAddVisibleViewDescriptors, this.viewContainerModel.onDidRemoveVisibleViewDescriptors), () => null, 0);
|
||||
return Event.map(modificationEvent, () => this.visibleRepositories);
|
||||
}
|
||||
|
||||
@@ -140,14 +140,14 @@ export class SCMViewPaneContainer extends ViewPaneContainer implements IViewMode
|
||||
|
||||
this._register(configurationService.onDidChangeConfiguration(e => {
|
||||
if (e.affectsConfiguration('scm.alwaysShowProviders') && configurationService.getValue<boolean>('scm.alwaysShowProviders')) {
|
||||
this.viewsDescriptors.setVisible(MainPane.ID, true);
|
||||
this.viewContainerModel.setVisible(MainPane.ID, true);
|
||||
}
|
||||
}));
|
||||
|
||||
this.repositoryCountKey = contextKeyService.createKey('scm.providerCount', 0);
|
||||
|
||||
this._register(this.viewsDescriptors.onDidAdd(this.onDidShowView, this));
|
||||
this._register(this.viewsDescriptors.onDidRemove(this.onDidHideView, this));
|
||||
this._register(this.viewContainerModel.onDidAddVisibleViewDescriptors(this.onDidShowView, this));
|
||||
this._register(this.viewContainerModel.onDidRemoveVisibleViewDescriptors(this.onDidHideView, this));
|
||||
}
|
||||
|
||||
create(parent: HTMLElement): void {
|
||||
@@ -214,8 +214,8 @@ export class SCMViewPaneContainer extends ViewPaneContainer implements IViewMode
|
||||
|
||||
@debounce(0)
|
||||
private afterOnDidHideView(): void {
|
||||
if (this.repositoryCountKey.get()! > 0 && this.viewDescriptors.every(d => !this.viewsDescriptors.isVisible(d.id))) {
|
||||
this.viewsDescriptors.setVisible(this.viewDescriptors[0].id, true);
|
||||
if (this.repositoryCountKey.get()! > 0 && this.viewDescriptors.every(d => !this.viewContainerModel.isVisible(d.id))) {
|
||||
this.viewContainerModel.setVisible(this.viewDescriptors[0].id, true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -282,9 +282,9 @@ export class SCMViewPaneContainer extends ViewPaneContainer implements IViewMode
|
||||
}
|
||||
|
||||
setVisibleRepositories(repositories: ISCMRepository[]): void {
|
||||
const visibleViewDescriptors = this.viewsDescriptors.visibleViewDescriptors;
|
||||
const visibleViewDescriptors = this.viewContainerModel.visibleViewDescriptors;
|
||||
|
||||
const toSetVisible = this.viewsDescriptors.activeViewDescriptors
|
||||
const toSetVisible = this.viewContainerModel.activeViewDescriptors
|
||||
.filter((d): d is RepositoryViewDescriptor => d instanceof RepositoryViewDescriptor && repositories.indexOf(d.repository) > -1 && visibleViewDescriptors.indexOf(d) === -1);
|
||||
|
||||
const toSetInvisible = visibleViewDescriptors
|
||||
@@ -302,11 +302,11 @@ export class SCMViewPaneContainer extends ViewPaneContainer implements IViewMode
|
||||
}
|
||||
}
|
||||
|
||||
this.viewsDescriptors.setVisible(viewDescriptor.id, false);
|
||||
this.viewContainerModel.setVisible(viewDescriptor.id, false);
|
||||
}
|
||||
|
||||
for (const viewDescriptor of toSetVisible) {
|
||||
this.viewsDescriptors.setVisible(viewDescriptor.id, true, size);
|
||||
this.viewContainerModel.setVisible(viewDescriptor.id, true, size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -704,7 +704,7 @@ export class TerminalService implements ITerminalService {
|
||||
const location = this._viewDescriptorService.getViewLocation(TERMINAL_VIEW_ID);
|
||||
if (location === ViewContainerLocation.Panel) {
|
||||
const panel = this._viewDescriptorService.getViewContainer(TERMINAL_VIEW_ID);
|
||||
if (panel && this._viewDescriptorService.getViewDescriptors(panel).activeViewDescriptors.length === 1) {
|
||||
if (panel && this._viewDescriptorService.getViewContainerModel(panel).activeViewDescriptors.length === 1) {
|
||||
this._layoutService.setPanelHidden(true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { ViewContainerLocation, IViewDescriptorService, ViewContainer, IViewsRegistry, IViewContainersRegistry, IViewDescriptor, Extensions as ViewExtensions, IViewDescriptorCollection, IAddedViewDescriptorRef, IViewDescriptorRef } from 'vs/workbench/common/views';
|
||||
import { IContextKey, RawContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { ViewContainerLocation, IViewDescriptorService, ViewContainer, IViewsRegistry, IViewContainersRegistry, IViewDescriptor, Extensions as ViewExtensions, IViewContainerModel, IAddedViewDescriptorRef, IViewDescriptorRef } from 'vs/workbench/common/views';
|
||||
import { IContextKey, RawContextKey, IContextKeyService, IReadableSet } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { IStorageService, StorageScope, IWorkspaceStorageChangeEvent } from 'vs/platform/storage/common/storage';
|
||||
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
@@ -17,68 +17,646 @@ import { IStorageKeysSyncRegistryService } from 'vs/platform/userDataSync/common
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { generateUuid } from 'vs/base/common/uuid';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { PersistentViewsModel, ViewDescriptorsModel } from 'vs/workbench/services/views/common/viewsModel';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { firstIndex, move } from 'vs/base/common/arrays';
|
||||
import { isUndefined, isUndefinedOrNull } from 'vs/base/common/types';
|
||||
import { values } from 'vs/base/common/map';
|
||||
import { isEqual } from 'vs/base/common/resources';
|
||||
|
||||
class ViewDescriptorCollection extends Disposable implements IViewDescriptorCollection {
|
||||
class CounterSet<T> implements IReadableSet<T> {
|
||||
|
||||
private readonly viewDescriptorsModel: ViewDescriptorsModel;
|
||||
private readonly viewsModel: PersistentViewsModel;
|
||||
private map = new Map<T, number>();
|
||||
|
||||
add(value: T): CounterSet<T> {
|
||||
this.map.set(value, (this.map.get(value) || 0) + 1);
|
||||
return this;
|
||||
}
|
||||
|
||||
delete(value: T): boolean {
|
||||
let counter = this.map.get(value) || 0;
|
||||
|
||||
if (counter === 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
counter--;
|
||||
|
||||
if (counter === 0) {
|
||||
this.map.delete(value);
|
||||
} else {
|
||||
this.map.set(value, counter);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
has(value: T): boolean {
|
||||
return this.map.has(value);
|
||||
}
|
||||
}
|
||||
|
||||
interface IStoredWorkspaceViewState {
|
||||
collapsed: boolean;
|
||||
isHidden: boolean;
|
||||
size?: number;
|
||||
order?: number;
|
||||
}
|
||||
|
||||
interface IStoredGlobalViewState {
|
||||
id: string;
|
||||
isHidden: boolean;
|
||||
order?: number;
|
||||
}
|
||||
|
||||
interface IViewDescriptorState {
|
||||
visibleGlobal: boolean | undefined;
|
||||
visibleWorkspace: boolean | undefined;
|
||||
collapsed: boolean | undefined;
|
||||
active: boolean
|
||||
order?: number;
|
||||
size?: number;
|
||||
}
|
||||
|
||||
class ViewDescriptorsState extends Disposable {
|
||||
|
||||
private readonly workspaceViewsStateStorageId: string;
|
||||
private readonly globalViewsStateStorageId: string;
|
||||
private readonly state: Map<string, IViewDescriptorState>;
|
||||
|
||||
private _onDidChangeStoredState = this._register(new Emitter<{ id: string, visible: boolean }[]>());
|
||||
readonly onDidChangeStoredState = this._onDidChangeStoredState.event;
|
||||
|
||||
constructor(
|
||||
viewContainerStorageId: string,
|
||||
@IStorageService private readonly storageService: IStorageService,
|
||||
@IStorageKeysSyncRegistryService storageKeysSyncRegistryService: IStorageKeysSyncRegistryService
|
||||
) {
|
||||
super();
|
||||
|
||||
this.globalViewsStateStorageId = `${viewContainerStorageId}.hidden`;
|
||||
this.workspaceViewsStateStorageId = viewContainerStorageId;
|
||||
storageKeysSyncRegistryService.registerStorageKey({ key: this.globalViewsStateStorageId, version: 1 });
|
||||
this._register(this.storageService.onDidChangeStorage(e => this.onDidStorageChange(e)));
|
||||
|
||||
this.state = this.initialize();
|
||||
}
|
||||
|
||||
set(id: string, state: IViewDescriptorState): void {
|
||||
this.state.set(id, state);
|
||||
}
|
||||
|
||||
get(id: string): IViewDescriptorState | undefined {
|
||||
return this.state.get(id);
|
||||
}
|
||||
|
||||
updateState(viewDescriptors: ReadonlyArray<IViewDescriptor>): void {
|
||||
this.updateWorkspaceState(viewDescriptors);
|
||||
this.updateGlobalState(viewDescriptors);
|
||||
}
|
||||
|
||||
private updateWorkspaceState(viewDescriptors: ReadonlyArray<IViewDescriptor>): void {
|
||||
const storedViewsStates: { [id: string]: IStoredWorkspaceViewState; } = JSON.parse(this.storageService.get(this.workspaceViewsStateStorageId, StorageScope.WORKSPACE, '{}'));
|
||||
for (const viewDescriptor of viewDescriptors) {
|
||||
const viewState = this.state.get(viewDescriptor.id);
|
||||
if (viewState) {
|
||||
storedViewsStates[viewDescriptor.id] = {
|
||||
collapsed: !!viewState.collapsed,
|
||||
isHidden: !viewState.visibleWorkspace,
|
||||
size: viewState.size,
|
||||
order: viewDescriptor.workspace && viewState ? viewState.order : undefined
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
if (Object.keys(storedViewsStates).length > 0) {
|
||||
this.storageService.store(this.workspaceViewsStateStorageId, JSON.stringify(storedViewsStates), StorageScope.WORKSPACE);
|
||||
} else {
|
||||
this.storageService.remove(this.workspaceViewsStateStorageId, StorageScope.WORKSPACE);
|
||||
}
|
||||
}
|
||||
|
||||
private updateGlobalState(viewDescriptors: ReadonlyArray<IViewDescriptor>): void {
|
||||
const storedGlobalState = this.getStoredGlobalState();
|
||||
for (const viewDescriptor of viewDescriptors) {
|
||||
const state = this.state.get(viewDescriptor.id);
|
||||
storedGlobalState.set(viewDescriptor.id, {
|
||||
id: viewDescriptor.id,
|
||||
isHidden: state && viewDescriptor.canToggleVisibility ? !state.visibleGlobal : false,
|
||||
order: !viewDescriptor.workspace && state ? state.order : undefined
|
||||
});
|
||||
}
|
||||
this.setStoredGlobalState(storedGlobalState);
|
||||
}
|
||||
|
||||
private onDidStorageChange(e: IWorkspaceStorageChangeEvent): void {
|
||||
if (e.key === this.globalViewsStateStorageId && e.scope === StorageScope.GLOBAL
|
||||
&& this.globalViewsStatesValue !== this.getStoredGlobalViewsStatesValue() /* This checks if current window changed the value or not */) {
|
||||
this._globalViewsStatesValue = undefined;
|
||||
const storedViewsVisibilityStates = this.getStoredGlobalState();
|
||||
const changedStates: { id: string, visible: boolean }[] = [];
|
||||
for (const [id, storedState] of storedViewsVisibilityStates) {
|
||||
const state = this.state.get(id);
|
||||
if (state) {
|
||||
if (state.visibleGlobal !== !storedState.isHidden) {
|
||||
changedStates.push({ id, visible: !storedState.isHidden });
|
||||
}
|
||||
}
|
||||
}
|
||||
if (changedStates.length) {
|
||||
this._onDidChangeStoredState.fire(changedStates);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private initialize(): Map<string, IViewDescriptorState> {
|
||||
const viewStates = new Map<string, IViewDescriptorState>();
|
||||
const workspaceViewsStates = <{ [id: string]: IStoredWorkspaceViewState; }>JSON.parse(this.storageService.get(this.workspaceViewsStateStorageId, StorageScope.WORKSPACE, '{}'));
|
||||
for (const id of Object.keys(workspaceViewsStates)) {
|
||||
const workspaceViewState = workspaceViewsStates[id];
|
||||
viewStates.set(id, {
|
||||
active: false,
|
||||
visibleGlobal: undefined,
|
||||
visibleWorkspace: isUndefined(workspaceViewState.isHidden) ? undefined : !workspaceViewState.isHidden,
|
||||
collapsed: workspaceViewState.collapsed,
|
||||
order: workspaceViewState.order,
|
||||
size: workspaceViewState.size,
|
||||
});
|
||||
}
|
||||
|
||||
// Migrate to `viewletStateStorageId`
|
||||
const value = this.storageService.get(this.globalViewsStateStorageId, StorageScope.WORKSPACE, '[]');
|
||||
const { state: workspaceVisibilityStates } = this.parseStoredGlobalState(value);
|
||||
if (workspaceVisibilityStates.size > 0) {
|
||||
for (const { id, isHidden } of values(workspaceVisibilityStates)) {
|
||||
let viewState = viewStates.get(id);
|
||||
// Not migrated to `viewletStateStorageId`
|
||||
if (viewState) {
|
||||
if (isUndefined(viewState.visibleWorkspace)) {
|
||||
viewState.visibleWorkspace = !isHidden;
|
||||
}
|
||||
} else {
|
||||
viewStates.set(id, {
|
||||
active: false,
|
||||
collapsed: undefined,
|
||||
visibleGlobal: undefined,
|
||||
visibleWorkspace: !isHidden,
|
||||
});
|
||||
}
|
||||
}
|
||||
this.storageService.remove(this.globalViewsStateStorageId, StorageScope.WORKSPACE);
|
||||
}
|
||||
|
||||
const { state, hasDuplicates } = this.parseStoredGlobalState(this.globalViewsStatesValue);
|
||||
if (hasDuplicates) {
|
||||
this.setStoredGlobalState(state);
|
||||
}
|
||||
for (const { id, isHidden, order } of values(state)) {
|
||||
let viewState = viewStates.get(id);
|
||||
if (viewState) {
|
||||
viewState.visibleGlobal = !isHidden;
|
||||
if (!isUndefined(order)) {
|
||||
viewState.order = order;
|
||||
}
|
||||
} else {
|
||||
viewStates.set(id, {
|
||||
active: false,
|
||||
visibleGlobal: !isHidden,
|
||||
order,
|
||||
collapsed: undefined,
|
||||
visibleWorkspace: undefined,
|
||||
});
|
||||
}
|
||||
}
|
||||
return viewStates;
|
||||
}
|
||||
|
||||
private getStoredGlobalState(): Map<string, IStoredGlobalViewState> {
|
||||
return this.parseStoredGlobalState(this.globalViewsStatesValue).state;
|
||||
}
|
||||
|
||||
private setStoredGlobalState(storedGlobalState: Map<string, IStoredGlobalViewState>): void {
|
||||
this.globalViewsStatesValue = JSON.stringify(values(storedGlobalState));
|
||||
}
|
||||
|
||||
private parseStoredGlobalState(value: string): { state: Map<string, IStoredGlobalViewState>, hasDuplicates: boolean } {
|
||||
const storedValue = <Array<string | IStoredGlobalViewState>>JSON.parse(value);
|
||||
let hasDuplicates = false;
|
||||
const state = storedValue.reduce((result, storedState) => {
|
||||
if (typeof storedState === 'string' /* migration */) {
|
||||
hasDuplicates = hasDuplicates || result.has(storedState);
|
||||
result.set(storedState, { id: storedState, isHidden: true });
|
||||
} else {
|
||||
hasDuplicates = hasDuplicates || result.has(storedState.id);
|
||||
result.set(storedState.id, storedState);
|
||||
}
|
||||
return result;
|
||||
}, new Map<string, IStoredGlobalViewState>());
|
||||
return { state, hasDuplicates };
|
||||
}
|
||||
|
||||
private _globalViewsStatesValue: string | undefined;
|
||||
private get globalViewsStatesValue(): string {
|
||||
if (!this._globalViewsStatesValue) {
|
||||
this._globalViewsStatesValue = this.getStoredGlobalViewsStatesValue();
|
||||
}
|
||||
|
||||
return this._globalViewsStatesValue;
|
||||
}
|
||||
|
||||
private set globalViewsStatesValue(globalViewsStatesValue: string) {
|
||||
if (this.globalViewsStatesValue !== globalViewsStatesValue) {
|
||||
this._globalViewsStatesValue = globalViewsStatesValue;
|
||||
this.setStoredGlobalViewsStatesValue(globalViewsStatesValue);
|
||||
}
|
||||
}
|
||||
|
||||
private getStoredGlobalViewsStatesValue(): string {
|
||||
return this.storageService.get(this.globalViewsStateStorageId, StorageScope.GLOBAL, '[]');
|
||||
}
|
||||
|
||||
private setStoredGlobalViewsStatesValue(value: string): void {
|
||||
this.storageService.store(this.globalViewsStateStorageId, value, StorageScope.GLOBAL);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
interface IViewDescriptorItem {
|
||||
viewDescriptor: IViewDescriptor;
|
||||
state: IViewDescriptorState;
|
||||
}
|
||||
|
||||
class ViewContainerModel extends Disposable implements IViewContainerModel {
|
||||
|
||||
private readonly contextKeys = new CounterSet<string>();
|
||||
private viewDescriptorItems: IViewDescriptorItem[] = [];
|
||||
private viewDescriptorsState: ViewDescriptorsState;
|
||||
|
||||
// Container Info
|
||||
private _title!: string;
|
||||
get title(): string { return this._title; }
|
||||
private _icon: URI | string | undefined;
|
||||
get icon(): URI | string | undefined { return this._icon; }
|
||||
|
||||
private _onDidChangeContainerInfo = this._register(new Emitter<{ title?: boolean, icon?: boolean }>());
|
||||
readonly onDidChangeContainerInfo = this._onDidChangeContainerInfo.event;
|
||||
|
||||
// All View Descriptors
|
||||
get allViewDescriptors(): ReadonlyArray<IViewDescriptor> { return this.viewDescriptorItems.map(item => item.viewDescriptor); }
|
||||
private _onDidChangeAllViewDescriptors = this._register(new Emitter<{ added: ReadonlyArray<IViewDescriptor>, removed: ReadonlyArray<IViewDescriptor> }>());
|
||||
readonly onDidChangeAllViewDescriptors = this._onDidChangeAllViewDescriptors.event;
|
||||
|
||||
// Active View Descriptors
|
||||
get activeViewDescriptors(): ReadonlyArray<IViewDescriptor> { return this.viewDescriptorItems.filter(item => item.state.active).map(item => item.viewDescriptor); }
|
||||
private _onDidChangeActiveViewDescriptors = this._register(new Emitter<{ added: ReadonlyArray<IViewDescriptor>, removed: ReadonlyArray<IViewDescriptor> }>());
|
||||
readonly onDidChangeActiveViewDescriptors = this._onDidChangeActiveViewDescriptors.event;
|
||||
|
||||
// Visible View Descriptors
|
||||
get visibleViewDescriptors(): ReadonlyArray<IViewDescriptor> { return this.viewDescriptorItems.filter(item => this.isViewDescriptorVisible(item)).map(item => item.viewDescriptor); }
|
||||
|
||||
private _onDidAddVisibleViewDescriptors = this._register(new Emitter<IAddedViewDescriptorRef[]>());
|
||||
readonly onDidAddVisibleViewDescriptors: Event<IAddedViewDescriptorRef[]> = this._onDidAddVisibleViewDescriptors.event;
|
||||
|
||||
private _onDidRemoveVisibleViewDescriptors = this._register(new Emitter<IViewDescriptorRef[]>());
|
||||
readonly onDidRemoveVisibleViewDescriptors: Event<IViewDescriptorRef[]> = this._onDidRemoveVisibleViewDescriptors.event;
|
||||
|
||||
private _onDidMoveVisibleViewDescriptors = this._register(new Emitter<{ from: IViewDescriptorRef; to: IViewDescriptorRef; }>());
|
||||
readonly onDidMoveVisibleViewDescriptors: Event<{ from: IViewDescriptorRef; to: IViewDescriptorRef; }> = this._onDidMoveVisibleViewDescriptors.event;
|
||||
|
||||
constructor(
|
||||
private readonly container: ViewContainer,
|
||||
@IInstantiationService instantiationService: IInstantiationService,
|
||||
@IContextKeyService private readonly contextKeyService: IContextKeyService,
|
||||
) {
|
||||
super();
|
||||
this.viewDescriptorsModel = instantiationService.createInstance(ViewDescriptorsModel);
|
||||
this.viewsModel = instantiationService.createInstance(PersistentViewsModel, container.storageId || `${container.id}.state`, this.viewDescriptorsModel);
|
||||
|
||||
this._register(Event.filter(contextKeyService.onDidChangeContext, e => e.affectsSome(this.contextKeys))(() => this.onDidChangeContext()));
|
||||
this.viewDescriptorsState = this._register(instantiationService.createInstance(ViewDescriptorsState, container.storageId || `${container.id}.state`));
|
||||
this._register(this.viewDescriptorsState.onDidChangeStoredState(items => this.updateVisibility(items)));
|
||||
|
||||
this._register(Event.any(
|
||||
this.onDidAddVisibleViewDescriptors,
|
||||
this.onDidRemoveVisibleViewDescriptors,
|
||||
this.onDidMoveVisibleViewDescriptors)
|
||||
(() => {
|
||||
this.viewDescriptorsState.updateState(this.allViewDescriptors);
|
||||
this.updateContainerInfo();
|
||||
}));
|
||||
|
||||
this.updateContainerInfo();
|
||||
}
|
||||
|
||||
get allViewDescriptors(): IViewDescriptor[] { return this.viewDescriptorsModel.allViewDescriptors; }
|
||||
get onDidChangeViews(): Event<{ added: IViewDescriptor[], removed: IViewDescriptor[] }> { return this.viewDescriptorsModel.onDidChangeViews; }
|
||||
|
||||
get activeViewDescriptors(): IViewDescriptor[] { return this.viewDescriptorsModel.activeViewDescriptors; }
|
||||
get _onDidChangeActiveViews(): Event<{ added: IViewDescriptor[], removed: IViewDescriptor[]; }> { return this.viewDescriptorsModel.onDidChangeActiveViews; }
|
||||
get onDidChangeActiveViews(): Event<ReadonlyArray<IViewDescriptor>> { return this.viewsModel.onDidChangeActiveViews; }
|
||||
|
||||
addViews(viewDescriptors: IViewDescriptor[]): void { return this.viewDescriptorsModel.addViews(viewDescriptors); }
|
||||
removeViews(viewDescriptors: IViewDescriptor[]): void { return this.viewDescriptorsModel.removeViews(viewDescriptors); }
|
||||
|
||||
get visibleViewDescriptors(): IViewDescriptor[] { return this.viewsModel.visibleViewDescriptors; }
|
||||
get onDidAdd(): Event<IAddedViewDescriptorRef[]> { return this.viewsModel.onDidAdd; }
|
||||
get onDidRemove(): Event<IViewDescriptorRef[]> { return this.viewsModel.onDidRemove; }
|
||||
get onDidMove(): Event<{ from: IViewDescriptorRef; to: IViewDescriptorRef; }> { return this.viewsModel.onDidMove; }
|
||||
|
||||
isVisible(id: string): boolean { return this.viewsModel.isVisible(id); }
|
||||
setVisible(id: string, visible: boolean, size?: number): void { return this.viewsModel.setVisible(id, visible, size); }
|
||||
|
||||
isCollapsed(id: string): boolean { return this.viewsModel.isCollapsed(id); }
|
||||
setCollapsed(id: string, collapsed: boolean): void { return this.viewsModel.setCollapsed(id, collapsed); }
|
||||
|
||||
private shouldUseContainerInfo(): boolean {
|
||||
if (this.allViewDescriptors.length === 0) {
|
||||
return true;
|
||||
private updateContainerInfo(): void {
|
||||
/* Use default container info if one of the visible view descriptors belongs to the current container by default */
|
||||
const useDefaultContainerInfo = this.visibleViewDescriptors.some(v => Registry.as<IViewsRegistry>(ViewExtensions.ViewsRegistry).getViewContainer(v.id) === this.container);
|
||||
const title = useDefaultContainerInfo ? this.container.name : this.visibleViewDescriptors[0]?.name || '';
|
||||
let titleChanged: boolean = false;
|
||||
if (this._title !== title) {
|
||||
this._title = title;
|
||||
titleChanged = true;
|
||||
}
|
||||
|
||||
if (this.visibleViewDescriptors.length === 0) {
|
||||
return true;
|
||||
const icon = useDefaultContainerInfo ? this.container.icon : this.visibleViewDescriptors[0]?.containerIcon || 'codicon-window';
|
||||
let iconChanged: boolean = false;
|
||||
if (URI.isUri(icon) && URI.isUri(this._icon) ? isEqual(icon, this._icon) : this._icon !== icon) {
|
||||
this._icon = icon;
|
||||
iconChanged = true;
|
||||
}
|
||||
|
||||
return this.allViewDescriptors.some(v => Registry.as<IViewsRegistry>(ViewExtensions.ViewsRegistry).getViewContainer(v.id) === this.container);
|
||||
if (titleChanged || iconChanged) {
|
||||
this._onDidChangeContainerInfo.fire({ title: titleChanged, icon: iconChanged });
|
||||
}
|
||||
}
|
||||
|
||||
getTitle(): string {
|
||||
return this.shouldUseContainerInfo() ? this.container.name : this.visibleViewDescriptors[0].name;
|
||||
isVisible(id: string): boolean {
|
||||
const viewDescriptorItem = this.viewDescriptorItems.filter(v => v.viewDescriptor.id === id)[0];
|
||||
if (!viewDescriptorItem) {
|
||||
throw new Error(`Unknown view ${id}`);
|
||||
}
|
||||
return this.isViewDescriptorVisible(viewDescriptorItem);
|
||||
}
|
||||
|
||||
getIcon(): URI | string | undefined {
|
||||
return this.shouldUseContainerInfo() ? this.container.icon : this.visibleViewDescriptors[0]?.containerIcon || 'codicon-window';
|
||||
setVisible(id: string, visible: boolean, size?: number): void {
|
||||
this.updateVisibility([{ id, visible, size }]);
|
||||
}
|
||||
|
||||
getSize(id: string): number | undefined { return this.viewsModel.getSize(id); }
|
||||
setSize(id: string, size: number): void { return this.viewsModel.setSize(id, size); }
|
||||
private updateVisibility(viewDescriptors: { id: string, visible: boolean, size?: number }[]): void {
|
||||
const added: IAddedViewDescriptorRef[] = [];
|
||||
const removed: IViewDescriptorRef[] = [];
|
||||
|
||||
move(from: string, to: string): void { return this.viewsModel.move(from, to); }
|
||||
for (const { visibleIndex, viewDescriptorItem, visible, size } of viewDescriptors.map(({ id, visible, size }) => ({ ...this.find(id), visible, size }))) {
|
||||
const viewDescriptor = viewDescriptorItem.viewDescriptor;
|
||||
|
||||
if (!viewDescriptor.canToggleVisibility) {
|
||||
throw new Error(`Can't toggle this view's visibility`);
|
||||
}
|
||||
|
||||
if (this.isViewDescriptorVisible(viewDescriptorItem) === visible) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (viewDescriptor.workspace) {
|
||||
viewDescriptorItem.state.visibleWorkspace = visible;
|
||||
} else {
|
||||
viewDescriptorItem.state.visibleGlobal = visible;
|
||||
}
|
||||
|
||||
if (typeof viewDescriptorItem.state.size === 'number') {
|
||||
viewDescriptorItem.state.size = size;
|
||||
}
|
||||
|
||||
if (visible) {
|
||||
added.push({ index: visibleIndex, viewDescriptor, size: viewDescriptorItem.state.size, collapsed: !!viewDescriptorItem.state.collapsed });
|
||||
} else {
|
||||
removed.push({ index: visibleIndex, viewDescriptor });
|
||||
}
|
||||
}
|
||||
|
||||
if (added.length) {
|
||||
this._onDidAddVisibleViewDescriptors.fire(added);
|
||||
}
|
||||
if (removed.length) {
|
||||
this._onDidRemoveVisibleViewDescriptors.fire(removed);
|
||||
}
|
||||
}
|
||||
|
||||
isCollapsed(id: string): boolean {
|
||||
return !!this.find(id).viewDescriptorItem.state.collapsed;
|
||||
}
|
||||
|
||||
setCollapsed(id: string, collapsed: boolean): void {
|
||||
const { viewDescriptorItem } = this.find(id);
|
||||
if (viewDescriptorItem.state.collapsed !== collapsed) {
|
||||
viewDescriptorItem.state.collapsed = collapsed;
|
||||
}
|
||||
this.viewDescriptorsState.updateState(this.allViewDescriptors);
|
||||
}
|
||||
|
||||
getSize(id: string): number | undefined {
|
||||
return this.find(id).viewDescriptorItem.state.size;
|
||||
}
|
||||
|
||||
setSize(id: string, size: number): void {
|
||||
const { viewDescriptorItem } = this.find(id);
|
||||
if (viewDescriptorItem.state.size !== size) {
|
||||
viewDescriptorItem.state.size = size;
|
||||
}
|
||||
this.viewDescriptorsState.updateState(this.allViewDescriptors);
|
||||
}
|
||||
|
||||
move(from: string, to: string): void {
|
||||
const fromIndex = firstIndex(this.viewDescriptorItems, v => v.viewDescriptor.id === from);
|
||||
const toIndex = firstIndex(this.viewDescriptorItems, v => v.viewDescriptor.id === to);
|
||||
|
||||
const fromViewDescriptor = this.viewDescriptorItems[fromIndex];
|
||||
const toViewDescriptor = this.viewDescriptorItems[toIndex];
|
||||
|
||||
move(this.viewDescriptorItems, fromIndex, toIndex);
|
||||
|
||||
for (let index = 0; index < this.viewDescriptorItems.length; index++) {
|
||||
this.viewDescriptorItems[index].state.order = index;
|
||||
}
|
||||
|
||||
this._onDidMoveVisibleViewDescriptors.fire({
|
||||
from: { index: fromIndex, viewDescriptor: fromViewDescriptor.viewDescriptor },
|
||||
to: { index: toIndex, viewDescriptor: toViewDescriptor.viewDescriptor }
|
||||
});
|
||||
}
|
||||
|
||||
add(viewDescriptors: IViewDescriptor[]): void {
|
||||
const addedItems: IViewDescriptorItem[] = [];
|
||||
const addedActiveDescriptors: IViewDescriptor[] = [];
|
||||
const addedVisibleItems: { index: number, viewDescriptor: IViewDescriptor, size?: number, collapsed: boolean; }[] = [];
|
||||
|
||||
for (const viewDescriptor of viewDescriptors) {
|
||||
|
||||
if (viewDescriptor.when) {
|
||||
for (const key of viewDescriptor.when.keys()) {
|
||||
this.contextKeys.add(key);
|
||||
}
|
||||
}
|
||||
|
||||
let state = this.viewDescriptorsState.get(viewDescriptor.id);
|
||||
if (state) {
|
||||
// set defaults if not set
|
||||
if (viewDescriptor.workspace) {
|
||||
state.visibleWorkspace = isUndefinedOrNull(state.visibleWorkspace) ? !viewDescriptor.hideByDefault : state.visibleWorkspace;
|
||||
} else {
|
||||
state.visibleGlobal = isUndefinedOrNull(state.visibleGlobal) ? !viewDescriptor.hideByDefault : state.visibleGlobal;
|
||||
}
|
||||
state.collapsed = isUndefinedOrNull(state.collapsed) ? !!viewDescriptor.collapsed : state.collapsed;
|
||||
} else {
|
||||
state = {
|
||||
active: false,
|
||||
visibleGlobal: !viewDescriptor.hideByDefault,
|
||||
visibleWorkspace: !viewDescriptor.hideByDefault,
|
||||
collapsed: !!viewDescriptor.collapsed,
|
||||
};
|
||||
}
|
||||
this.viewDescriptorsState.set(viewDescriptor.id, state);
|
||||
state.active = this.contextKeyService.contextMatchesRules(viewDescriptor.when);
|
||||
addedItems.push({ viewDescriptor, state });
|
||||
|
||||
if (state.active) {
|
||||
addedActiveDescriptors.push(viewDescriptor);
|
||||
}
|
||||
}
|
||||
|
||||
this.viewDescriptorItems.push(...addedItems);
|
||||
this.viewDescriptorItems.sort(this.compareViewDescriptors.bind(this));
|
||||
|
||||
for (const viewDescriptorItem of addedItems) {
|
||||
if (this.isViewDescriptorVisible(viewDescriptorItem)) {
|
||||
const { visibleIndex } = this.find(viewDescriptorItem.viewDescriptor.id);
|
||||
addedVisibleItems.push({ index: visibleIndex, viewDescriptor: viewDescriptorItem.viewDescriptor, size: viewDescriptorItem.state.size, collapsed: !!viewDescriptorItem.state.collapsed });
|
||||
}
|
||||
}
|
||||
|
||||
this._onDidChangeAllViewDescriptors.fire({ added: addedItems.map(({ viewDescriptor }) => viewDescriptor), removed: [] });
|
||||
if (addedActiveDescriptors.length) {
|
||||
this._onDidChangeActiveViewDescriptors.fire(({ added: addedActiveDescriptors, removed: [] }));
|
||||
}
|
||||
if (addedVisibleItems.length) {
|
||||
this._onDidAddVisibleViewDescriptors.fire(addedVisibleItems);
|
||||
}
|
||||
}
|
||||
|
||||
remove(viewDescriptors: IViewDescriptor[]): void {
|
||||
const removed: IViewDescriptor[] = [];
|
||||
const removedItems: IViewDescriptorItem[] = [];
|
||||
const removedActiveDescriptors: IViewDescriptor[] = [];
|
||||
const removedVisibleItems: { index: number, viewDescriptor: IViewDescriptor; }[] = [];
|
||||
|
||||
for (const viewDescriptor of viewDescriptors) {
|
||||
if (viewDescriptor.when) {
|
||||
for (const key of viewDescriptor.when.keys()) {
|
||||
this.contextKeys.delete(key);
|
||||
}
|
||||
}
|
||||
const index = firstIndex(this.viewDescriptorItems, i => i.viewDescriptor.id === viewDescriptor.id);
|
||||
if (index !== -1) {
|
||||
removed.push(viewDescriptor);
|
||||
const viewDescriptorItem = this.viewDescriptorItems[index];
|
||||
if (viewDescriptorItem.state.active) {
|
||||
removedActiveDescriptors.push(viewDescriptorItem.viewDescriptor);
|
||||
}
|
||||
if (this.isViewDescriptorVisible(viewDescriptorItem)) {
|
||||
const { visibleIndex } = this.find(viewDescriptorItem.viewDescriptor.id);
|
||||
removedVisibleItems.push({ index: visibleIndex, viewDescriptor: viewDescriptorItem.viewDescriptor });
|
||||
}
|
||||
removedItems.push(viewDescriptorItem);
|
||||
}
|
||||
}
|
||||
|
||||
removedItems.forEach(item => this.viewDescriptorItems.splice(this.viewDescriptorItems.indexOf(item), 1));
|
||||
|
||||
this._onDidChangeAllViewDescriptors.fire({ added: [], removed });
|
||||
if (removedActiveDescriptors.length) {
|
||||
this._onDidChangeActiveViewDescriptors.fire(({ added: [], removed: removedActiveDescriptors }));
|
||||
}
|
||||
if (removedVisibleItems.length) {
|
||||
this._onDidRemoveVisibleViewDescriptors.fire(removedVisibleItems);
|
||||
}
|
||||
}
|
||||
|
||||
private onDidChangeContext(): void {
|
||||
const addedActiveItems: { item: IViewDescriptorItem, wasVisible: boolean }[] = [];
|
||||
const removedActiveItems: { item: IViewDescriptorItem, wasVisible: boolean }[] = [];
|
||||
const removedVisibleItems: { index: number, viewDescriptor: IViewDescriptor; }[] = [];
|
||||
const addedVisibleItems: { index: number, viewDescriptor: IViewDescriptor, size?: number, collapsed: boolean; }[] = [];
|
||||
|
||||
for (const item of this.viewDescriptorItems) {
|
||||
const wasActive = item.state.active;
|
||||
const wasVisible = this.isViewDescriptorVisible(item);
|
||||
const isActive = this.contextKeyService.contextMatchesRules(item.viewDescriptor.when);
|
||||
if (wasActive !== isActive) {
|
||||
if (isActive) {
|
||||
addedActiveItems.push({ item, wasVisible });
|
||||
} else {
|
||||
removedActiveItems.push({ item, wasVisible });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (const { item, wasVisible } of removedActiveItems) {
|
||||
if (wasVisible) {
|
||||
const { visibleIndex } = this.find(item.viewDescriptor.id);
|
||||
removedVisibleItems.push({ index: visibleIndex, viewDescriptor: item.viewDescriptor });
|
||||
}
|
||||
}
|
||||
|
||||
// Update the State
|
||||
removedActiveItems.forEach(({ item }) => item.state.active = false);
|
||||
addedActiveItems.forEach(({ item }) => item.state.active = true);
|
||||
|
||||
for (const { item, wasVisible } of addedActiveItems) {
|
||||
if (wasVisible !== this.isViewDescriptorVisibleWhenActive(item)) {
|
||||
const { visibleIndex } = this.find(item.viewDescriptor.id);
|
||||
addedVisibleItems.push({ index: visibleIndex, viewDescriptor: item.viewDescriptor, size: item.state.size, collapsed: !!item.state.collapsed });
|
||||
}
|
||||
}
|
||||
|
||||
if (addedActiveItems.length || removedActiveItems.length) {
|
||||
this._onDidChangeActiveViewDescriptors.fire(({ added: addedActiveItems.map(({ item }) => item.viewDescriptor), removed: removedActiveItems.map(({ item }) => item.viewDescriptor) }));
|
||||
}
|
||||
if (removedVisibleItems.length) {
|
||||
this._onDidRemoveVisibleViewDescriptors.fire(removedVisibleItems);
|
||||
}
|
||||
if (addedVisibleItems.length) {
|
||||
this._onDidAddVisibleViewDescriptors.fire(addedVisibleItems);
|
||||
}
|
||||
}
|
||||
|
||||
private isViewDescriptorVisible(viewDescriptorItem: IViewDescriptorItem): boolean {
|
||||
if (!viewDescriptorItem.state.active) {
|
||||
return false;
|
||||
}
|
||||
return this.isViewDescriptorVisibleWhenActive(viewDescriptorItem);
|
||||
}
|
||||
|
||||
private isViewDescriptorVisibleWhenActive(viewDescriptorItem: IViewDescriptorItem): boolean {
|
||||
if (viewDescriptorItem.viewDescriptor.workspace) {
|
||||
return !!viewDescriptorItem.state.visibleWorkspace;
|
||||
}
|
||||
return !!viewDescriptorItem.state.visibleGlobal;
|
||||
}
|
||||
|
||||
private find(id: string): { index: number, visibleIndex: number, viewDescriptorItem: IViewDescriptorItem; } {
|
||||
for (let i = 0, visibleIndex = 0; i < this.viewDescriptorItems.length; i++) {
|
||||
const viewDescriptorItem = this.viewDescriptorItems[i];
|
||||
if (viewDescriptorItem.viewDescriptor.id === id) {
|
||||
return { index: i, visibleIndex, viewDescriptorItem: viewDescriptorItem };
|
||||
}
|
||||
if (this.isViewDescriptorVisible(viewDescriptorItem)) {
|
||||
visibleIndex++;
|
||||
}
|
||||
}
|
||||
throw new Error(`view descriptor ${id} not found`);
|
||||
}
|
||||
|
||||
private compareViewDescriptors(a: IViewDescriptorItem, b: IViewDescriptorItem): number {
|
||||
if (a.viewDescriptor.id === b.viewDescriptor.id) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return (this.getViewOrder(a) - this.getViewOrder(b)) || this.getGroupOrderResult(a.viewDescriptor, b.viewDescriptor);
|
||||
}
|
||||
|
||||
private getViewOrder(viewDescriptorItem: IViewDescriptorItem): number {
|
||||
const viewOrder = typeof viewDescriptorItem.state.order === 'number' ? viewDescriptorItem.state.order : viewDescriptorItem.viewDescriptor.order;
|
||||
return typeof viewOrder === 'number' ? viewOrder : Number.MAX_VALUE;
|
||||
}
|
||||
|
||||
private getGroupOrderResult(a: IViewDescriptor, b: IViewDescriptor) {
|
||||
if (!a.group || !b.group) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (a.group === b.group) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return a.group < b.group ? -1 : 1;
|
||||
}
|
||||
}
|
||||
|
||||
interface ICachedViewContainerInfo {
|
||||
@@ -99,7 +677,7 @@ export class ViewDescriptorService extends Disposable implements IViewDescriptor
|
||||
private readonly _onDidChangeLocation: Emitter<{ views: IViewDescriptor[], from: ViewContainerLocation, to: ViewContainerLocation }> = this._register(new Emitter<{ views: IViewDescriptor[], from: ViewContainerLocation, to: ViewContainerLocation }>());
|
||||
readonly onDidChangeLocation: Event<{ views: IViewDescriptor[], from: ViewContainerLocation, to: ViewContainerLocation }> = this._onDidChangeLocation.event;
|
||||
|
||||
private readonly viewDescriptorCollections: Map<ViewContainer, { viewDescriptorCollection: ViewDescriptorCollection, disposable: IDisposable; }>;
|
||||
private readonly viewContainerModels: Map<ViewContainer, { viewContainerModel: ViewContainerModel, disposable: IDisposable; }>;
|
||||
private readonly activeViewContextKeys: Map<string, IContextKey<boolean>>;
|
||||
private readonly movableViewContextKeys: Map<string, IContextKey<boolean>>;
|
||||
private readonly defaultViewLocationContextKeys: Map<string, IContextKey<boolean>>;
|
||||
@@ -136,7 +714,7 @@ export class ViewDescriptorService extends Disposable implements IViewDescriptor
|
||||
super();
|
||||
|
||||
storageKeysSyncRegistryService.registerStorageKey({ key: ViewDescriptorService.CACHED_VIEW_POSITIONS, version: 1 });
|
||||
this.viewDescriptorCollections = new Map<ViewContainer, { viewDescriptorCollection: ViewDescriptorCollection, disposable: IDisposable; }>();
|
||||
this.viewContainerModels = new Map<ViewContainer, { viewContainerModel: ViewContainerModel, disposable: IDisposable; }>();
|
||||
this.activeViewContextKeys = new Map<string, IContextKey<boolean>>();
|
||||
this.movableViewContextKeys = new Map<string, IContextKey<boolean>>();
|
||||
this.defaultViewLocationContextKeys = new Map<string, IContextKey<boolean>>();
|
||||
@@ -160,8 +738,8 @@ export class ViewDescriptorService extends Disposable implements IViewDescriptor
|
||||
this._register(this.viewContainersRegistry.onDidRegister(({ viewContainer }) => this.onDidRegisterViewContainer(viewContainer)));
|
||||
this._register(this.viewContainersRegistry.onDidDeregister(({ viewContainer }) => this.onDidDeregisterViewContainer(viewContainer)));
|
||||
this._register(toDisposable(() => {
|
||||
this.viewDescriptorCollections.forEach(({ disposable }) => disposable.dispose());
|
||||
this.viewDescriptorCollections.clear();
|
||||
this.viewContainerModels.forEach(({ disposable }) => disposable.dispose());
|
||||
this.viewContainerModels.clear();
|
||||
}));
|
||||
|
||||
this._register(this.storageService.onDidChangeStorage((e) => { this.onDidStorageChange(e); }));
|
||||
@@ -176,7 +754,7 @@ export class ViewDescriptorService extends Disposable implements IViewDescriptor
|
||||
const containerData = groupedViews.get(containerId)!;
|
||||
|
||||
// The container has not been registered yet
|
||||
if (!viewContainer || !this.viewDescriptorCollections.has(viewContainer)) {
|
||||
if (!viewContainer || !this.viewContainerModels.has(viewContainer)) {
|
||||
if (containerData.cachedContainerInfo && this.shouldGenerateContainer(containerData.cachedContainerInfo)) {
|
||||
const containerInfo = containerData.cachedContainerInfo;
|
||||
|
||||
@@ -198,7 +776,7 @@ export class ViewDescriptorService extends Disposable implements IViewDescriptor
|
||||
const viewContainer = this.viewContainersRegistry.get(viewContainerId);
|
||||
|
||||
// The container has not been registered yet
|
||||
if (!viewContainer || !this.viewDescriptorCollections.has(viewContainer)) {
|
||||
if (!viewContainer || !this.viewContainerModels.has(viewContainer)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -321,8 +899,8 @@ export class ViewDescriptorService extends Disposable implements IViewDescriptor
|
||||
return this.viewsRegistry.getViewContainer(viewId) ?? null;
|
||||
}
|
||||
|
||||
getViewDescriptors(container: ViewContainer): ViewDescriptorCollection {
|
||||
return this.getOrRegisterViewDescriptorCollection(container);
|
||||
getViewContainerModel(container: ViewContainer): ViewContainerModel {
|
||||
return this.getOrRegisterViewContainerModel(container);
|
||||
}
|
||||
|
||||
moveViewToLocation(view: IViewDescriptor, location: ViewContainerLocation): void {
|
||||
@@ -456,8 +1034,8 @@ export class ViewDescriptorService extends Disposable implements IViewDescriptor
|
||||
|
||||
// If a value is not present in the cache, it must be reset to default
|
||||
this.viewContainersRegistry.all.forEach(viewContainer => {
|
||||
const viewDescriptorCollection = this.getViewDescriptors(viewContainer);
|
||||
viewDescriptorCollection.allViewDescriptors.forEach(viewDescriptor => {
|
||||
const viewContainerModel = this.getViewContainerModel(viewContainer);
|
||||
viewContainerModel.allViewDescriptors.forEach(viewDescriptor => {
|
||||
if (!newCachedPositions.has(viewDescriptor.id)) {
|
||||
const currentContainer = this.getViewContainer(viewDescriptor.id);
|
||||
const defaultContainer = this.getDefaultContainer(viewDescriptor.id);
|
||||
@@ -492,8 +1070,8 @@ export class ViewDescriptorService extends Disposable implements IViewDescriptor
|
||||
|
||||
private saveViewPositionsToCache(): void {
|
||||
this.viewContainersRegistry.all.forEach(viewContainer => {
|
||||
const viewDescriptorCollection = this.getViewDescriptors(viewContainer);
|
||||
viewDescriptorCollection.allViewDescriptors.forEach(viewDescriptor => {
|
||||
const viewContainerModel = this.getViewContainerModel(viewContainer);
|
||||
viewContainerModel.allViewDescriptors.forEach(viewDescriptor => {
|
||||
const containerLocation = this.getViewContainerLocation(viewContainer);
|
||||
this.cachedViewInfo.set(viewDescriptor.id, {
|
||||
containerId: viewContainer.id,
|
||||
@@ -540,20 +1118,20 @@ export class ViewDescriptorService extends Disposable implements IViewDescriptor
|
||||
}
|
||||
|
||||
private onDidRegisterViewContainer(viewContainer: ViewContainer): void {
|
||||
this.getOrRegisterViewDescriptorCollection(viewContainer);
|
||||
this.getOrRegisterViewContainerModel(viewContainer);
|
||||
}
|
||||
|
||||
private getOrRegisterViewDescriptorCollection(viewContainer: ViewContainer): ViewDescriptorCollection {
|
||||
let viewDescriptorCollection = this.viewDescriptorCollections.get(viewContainer)?.viewDescriptorCollection;
|
||||
private getOrRegisterViewContainerModel(viewContainer: ViewContainer): ViewContainerModel {
|
||||
let viewContainerModel = this.viewContainerModels.get(viewContainer)?.viewContainerModel;
|
||||
|
||||
if (!viewDescriptorCollection) {
|
||||
if (!viewContainerModel) {
|
||||
const disposables = new DisposableStore();
|
||||
viewDescriptorCollection = disposables.add(this.instantiationService.createInstance(ViewDescriptorCollection, viewContainer));
|
||||
viewContainerModel = disposables.add(this.instantiationService.createInstance(ViewContainerModel, viewContainer));
|
||||
|
||||
this.onDidChangeActiveViews({ added: viewDescriptorCollection.activeViewDescriptors, removed: [] });
|
||||
viewDescriptorCollection._onDidChangeActiveViews(changed => this.onDidChangeActiveViews(changed), this, disposables);
|
||||
this.onDidChangeActiveViews({ added: viewContainerModel.activeViewDescriptors, removed: [] });
|
||||
viewContainerModel.onDidChangeActiveViewDescriptors(changed => this.onDidChangeActiveViews(changed), this, disposables);
|
||||
|
||||
this.viewDescriptorCollections.set(viewContainer, { viewDescriptorCollection, disposable: disposables });
|
||||
this.viewContainerModels.set(viewContainer, { viewContainerModel: viewContainerModel, disposable: disposables });
|
||||
|
||||
const viewsToRegister = this.getViewsByContainer(viewContainer);
|
||||
if (viewsToRegister.length) {
|
||||
@@ -562,18 +1140,18 @@ export class ViewDescriptorService extends Disposable implements IViewDescriptor
|
||||
}
|
||||
}
|
||||
|
||||
return viewDescriptorCollection;
|
||||
return viewContainerModel;
|
||||
}
|
||||
|
||||
private onDidDeregisterViewContainer(viewContainer: ViewContainer): void {
|
||||
const viewDescriptorCollectionItem = this.viewDescriptorCollections.get(viewContainer);
|
||||
if (viewDescriptorCollectionItem) {
|
||||
viewDescriptorCollectionItem.disposable.dispose();
|
||||
this.viewDescriptorCollections.delete(viewContainer);
|
||||
const viewContainerModelItem = this.viewContainerModels.get(viewContainer);
|
||||
if (viewContainerModelItem) {
|
||||
viewContainerModelItem.disposable.dispose();
|
||||
this.viewContainerModels.delete(viewContainer);
|
||||
}
|
||||
}
|
||||
|
||||
private onDidChangeActiveViews({ added, removed }: { added: IViewDescriptor[], removed: IViewDescriptor[]; }): void {
|
||||
private onDidChangeActiveViews({ added, removed }: { added: ReadonlyArray<IViewDescriptor>, removed: ReadonlyArray<IViewDescriptor>; }): void {
|
||||
added.forEach(viewDescriptor => this.getOrCreateActiveViewContextKey(viewDescriptor).set(true));
|
||||
removed.forEach(viewDescriptor => this.getOrCreateActiveViewContextKey(viewDescriptor).set(false));
|
||||
}
|
||||
@@ -586,7 +1164,7 @@ export class ViewDescriptorService extends Disposable implements IViewDescriptor
|
||||
this.getOrCreateDefaultViewLocationContextKey(view).set(this.getDefaultContainer(view.id) === container);
|
||||
});
|
||||
|
||||
this.getViewDescriptors(container).addViews(views);
|
||||
this.getViewContainerModel(container).add(views);
|
||||
}
|
||||
|
||||
private removeViews(container: ViewContainer, views: IViewDescriptor[]): void {
|
||||
@@ -594,7 +1172,7 @@ export class ViewDescriptorService extends Disposable implements IViewDescriptor
|
||||
views.forEach(view => this.getOrCreateDefaultViewLocationContextKey(view).set(false));
|
||||
|
||||
// Remove the views
|
||||
this.getViewDescriptors(container).removeViews(views);
|
||||
this.getViewContainerModel(container).remove(views);
|
||||
}
|
||||
|
||||
private getOrCreateActiveViewContextKey(viewDescriptor: IViewDescriptor): IContextKey<boolean> {
|
||||
|
||||
@@ -1,648 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { IViewDescriptor, IAddedViewDescriptorRef, IViewDescriptorRef } from 'vs/workbench/common/views';
|
||||
import { IStorageService, StorageScope, IWorkspaceStorageChangeEvent } from 'vs/platform/storage/common/storage';
|
||||
import { Event, Emitter } from 'vs/base/common/event';
|
||||
import { firstIndex, move } from 'vs/base/common/arrays';
|
||||
import { isUndefinedOrNull, isUndefined } from 'vs/base/common/types';
|
||||
import { values } from 'vs/base/common/map';
|
||||
import { IStorageKeysSyncRegistryService } from 'vs/platform/userDataSync/common/storageKeys';
|
||||
import { IContextKeyChangeEvent, IContextKeyService, IReadableSet } from 'vs/platform/contextkey/common/contextkey';
|
||||
|
||||
class CounterSet<T> implements IReadableSet<T> {
|
||||
|
||||
private map = new Map<T, number>();
|
||||
|
||||
add(value: T): CounterSet<T> {
|
||||
this.map.set(value, (this.map.get(value) || 0) + 1);
|
||||
return this;
|
||||
}
|
||||
|
||||
delete(value: T): boolean {
|
||||
let counter = this.map.get(value) || 0;
|
||||
|
||||
if (counter === 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
counter--;
|
||||
|
||||
if (counter === 0) {
|
||||
this.map.delete(value);
|
||||
} else {
|
||||
this.map.set(value, counter);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
has(value: T): boolean {
|
||||
return this.map.has(value);
|
||||
}
|
||||
}
|
||||
|
||||
interface IViewItem {
|
||||
viewDescriptor: IViewDescriptor;
|
||||
active: boolean;
|
||||
}
|
||||
|
||||
export class ViewDescriptorsModel extends Disposable {
|
||||
|
||||
private contextKeys = new CounterSet<string>();
|
||||
private items: IViewItem[] = [];
|
||||
|
||||
private _onDidChangeViews: Emitter<{ added: IViewDescriptor[], removed: IViewDescriptor[]; }> = this._register(new Emitter<{ added: IViewDescriptor[], removed: IViewDescriptor[]; }>());
|
||||
readonly onDidChangeViews: Event<{ added: IViewDescriptor[], removed: IViewDescriptor[]; }> = this._onDidChangeViews.event;
|
||||
|
||||
private _onDidChangeActiveViews: Emitter<{ added: IViewDescriptor[], removed: IViewDescriptor[]; }> = this._register(new Emitter<{ added: IViewDescriptor[], removed: IViewDescriptor[]; }>());
|
||||
readonly onDidChangeActiveViews: Event<{ added: IViewDescriptor[], removed: IViewDescriptor[]; }> = this._onDidChangeActiveViews.event;
|
||||
|
||||
get activeViewDescriptors(): IViewDescriptor[] {
|
||||
return this.items
|
||||
.filter(i => i.active)
|
||||
.map(i => i.viewDescriptor);
|
||||
}
|
||||
|
||||
get allViewDescriptors(): IViewDescriptor[] {
|
||||
return this.items.map(i => i.viewDescriptor);
|
||||
}
|
||||
|
||||
constructor(
|
||||
@IContextKeyService private readonly contextKeyService: IContextKeyService,
|
||||
) {
|
||||
super();
|
||||
this._register(Event.filter(contextKeyService.onDidChangeContext, e => e.affectsSome(this.contextKeys))(this.onContextChanged, this));
|
||||
}
|
||||
|
||||
addViews(viewDescriptors: IViewDescriptor[]): void {
|
||||
const added: IViewDescriptor[] = [];
|
||||
|
||||
for (const viewDescriptor of viewDescriptors) {
|
||||
const item = {
|
||||
viewDescriptor,
|
||||
active: this.isViewDescriptorActive(viewDescriptor) // TODO: should read from some state?
|
||||
};
|
||||
|
||||
this.items.push(item);
|
||||
|
||||
if (viewDescriptor.when) {
|
||||
for (const key of viewDescriptor.when.keys()) {
|
||||
this.contextKeys.add(key);
|
||||
}
|
||||
}
|
||||
|
||||
if (item.active) {
|
||||
added.push(viewDescriptor);
|
||||
}
|
||||
}
|
||||
|
||||
this._onDidChangeViews.fire({ added: viewDescriptors, removed: [] });
|
||||
|
||||
if (added.length) {
|
||||
this._onDidChangeActiveViews.fire({ added, removed: [] });
|
||||
}
|
||||
}
|
||||
|
||||
removeViews(viewDescriptors: IViewDescriptor[]): void {
|
||||
const removed: IViewDescriptor[] = [];
|
||||
|
||||
for (const viewDescriptor of viewDescriptors) {
|
||||
const index = firstIndex(this.items, i => i.viewDescriptor.id === viewDescriptor.id);
|
||||
|
||||
if (index === -1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const item = this.items[index];
|
||||
this.items.splice(index, 1);
|
||||
|
||||
if (viewDescriptor.when) {
|
||||
for (const key of viewDescriptor.when.keys()) {
|
||||
this.contextKeys.delete(key);
|
||||
}
|
||||
}
|
||||
|
||||
if (item.active) {
|
||||
removed.push(viewDescriptor);
|
||||
}
|
||||
}
|
||||
|
||||
this._onDidChangeViews.fire({ added: [], removed: viewDescriptors });
|
||||
|
||||
if (removed.length) {
|
||||
this._onDidChangeActiveViews.fire({ added: [], removed });
|
||||
}
|
||||
}
|
||||
|
||||
private onContextChanged(event: IContextKeyChangeEvent): void {
|
||||
const removed: IViewDescriptor[] = [];
|
||||
const added: IViewDescriptor[] = [];
|
||||
|
||||
for (const item of this.items) {
|
||||
const active = this.isViewDescriptorActive(item.viewDescriptor);
|
||||
|
||||
if (item.active !== active) {
|
||||
if (active) {
|
||||
added.push(item.viewDescriptor);
|
||||
} else {
|
||||
removed.push(item.viewDescriptor);
|
||||
}
|
||||
}
|
||||
|
||||
item.active = active;
|
||||
}
|
||||
|
||||
if (added.length || removed.length) {
|
||||
this._onDidChangeActiveViews.fire({ added, removed });
|
||||
}
|
||||
}
|
||||
|
||||
private isViewDescriptorActive(viewDescriptor: IViewDescriptor): boolean {
|
||||
return !viewDescriptor.when || this.contextKeyService.contextMatchesRules(viewDescriptor.when);
|
||||
}
|
||||
}
|
||||
|
||||
export interface IViewState {
|
||||
visibleGlobal: boolean | undefined;
|
||||
visibleWorkspace: boolean | undefined;
|
||||
collapsed: boolean | undefined;
|
||||
order?: number;
|
||||
size?: number;
|
||||
}
|
||||
|
||||
export class ViewsModel extends Disposable {
|
||||
|
||||
private _viewDescriptors: IViewDescriptor[] = [];
|
||||
get viewDescriptors(): ReadonlyArray<IViewDescriptor> {
|
||||
return this._viewDescriptors;
|
||||
}
|
||||
|
||||
get visibleViewDescriptors(): IViewDescriptor[] {
|
||||
return this.viewDescriptors.filter(v => this.isViewDescriptorVisible(v)).sort((a, b) => {
|
||||
const aIndex = this.viewStates.get(a.id)?.order;
|
||||
const bIndex = this.viewStates.get(b.id)?.order;
|
||||
|
||||
if (aIndex === undefined) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (bIndex === undefined) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return aIndex - bIndex;
|
||||
});
|
||||
}
|
||||
|
||||
private _onDidAdd = this._register(new Emitter<IAddedViewDescriptorRef[]>());
|
||||
readonly onDidAdd: Event<IAddedViewDescriptorRef[]> = this._onDidAdd.event;
|
||||
|
||||
private _onDidRemove = this._register(new Emitter<IViewDescriptorRef[]>());
|
||||
readonly onDidRemove: Event<IViewDescriptorRef[]> = this._onDidRemove.event;
|
||||
|
||||
private _onDidMove = this._register(new Emitter<{ from: IViewDescriptorRef; to: IViewDescriptorRef; }>());
|
||||
readonly onDidMove: Event<{ from: IViewDescriptorRef; to: IViewDescriptorRef; }> = this._onDidMove.event;
|
||||
|
||||
private _onDidChangeViewState = this._register(new Emitter<IViewDescriptorRef>());
|
||||
protected readonly onDidChangeViewState: Event<IViewDescriptorRef> = this._onDidChangeViewState.event;
|
||||
|
||||
private _onDidChangeActiveViews = this._register(new Emitter<ReadonlyArray<IViewDescriptor>>());
|
||||
readonly onDidChangeActiveViews: Event<ReadonlyArray<IViewDescriptor>> = this._onDidChangeActiveViews.event;
|
||||
|
||||
constructor(
|
||||
viewDescriptorCollection: ViewDescriptorsModel,
|
||||
protected viewStates = new Map<string, IViewState>(),
|
||||
) {
|
||||
super();
|
||||
this._register(viewDescriptorCollection.onDidChangeActiveViews(() => this.onDidChangeViewDescriptors(viewDescriptorCollection.activeViewDescriptors)));
|
||||
this.onDidChangeViewDescriptors(viewDescriptorCollection.activeViewDescriptors);
|
||||
}
|
||||
|
||||
isVisible(id: string): boolean {
|
||||
const viewDescriptor = this.viewDescriptors.filter(v => v.id === id)[0];
|
||||
|
||||
if (!viewDescriptor) {
|
||||
throw new Error(`Unknown view ${id}`);
|
||||
}
|
||||
|
||||
return this.isViewDescriptorVisible(viewDescriptor);
|
||||
}
|
||||
|
||||
setVisible(id: string, visible: boolean, size?: number): void {
|
||||
this.doSetVisible([{ id, visible, size }]);
|
||||
}
|
||||
|
||||
protected doSetVisible(viewDescriptors: { id: string, visible: boolean, size?: number }[]): void {
|
||||
const added: IAddedViewDescriptorRef[] = [];
|
||||
const removed: IViewDescriptorRef[] = [];
|
||||
|
||||
for (const { visibleIndex, viewDescriptor, state, visible, size } of viewDescriptors.map(({ id, visible, size }) => ({ ...this.find(id), visible, size }))) {
|
||||
|
||||
if (!viewDescriptor.canToggleVisibility) {
|
||||
throw new Error(`Can't toggle this view's visibility`);
|
||||
}
|
||||
|
||||
if (this.isViewDescriptorVisible(viewDescriptor) === visible) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (viewDescriptor.workspace) {
|
||||
state.visibleWorkspace = visible;
|
||||
} else {
|
||||
state.visibleGlobal = visible;
|
||||
}
|
||||
|
||||
if (typeof size === 'number') {
|
||||
state.size = size;
|
||||
}
|
||||
|
||||
if (visible) {
|
||||
added.push({ index: visibleIndex, viewDescriptor, size: state.size, collapsed: !!state.collapsed });
|
||||
} else {
|
||||
removed.push({ index: visibleIndex, viewDescriptor });
|
||||
}
|
||||
}
|
||||
|
||||
if (added.length) {
|
||||
this._onDidAdd.fire(added);
|
||||
}
|
||||
if (removed.length) {
|
||||
this._onDidRemove.fire(removed);
|
||||
}
|
||||
}
|
||||
|
||||
isCollapsed(id: string): boolean {
|
||||
const state = this.viewStates.get(id);
|
||||
|
||||
if (!state) {
|
||||
throw new Error(`Unknown view ${id}`);
|
||||
}
|
||||
|
||||
return !!state.collapsed;
|
||||
}
|
||||
|
||||
setCollapsed(id: string, collapsed: boolean): void {
|
||||
const { index, state, viewDescriptor } = this.find(id);
|
||||
if (state.collapsed !== collapsed) {
|
||||
state.collapsed = collapsed;
|
||||
this._onDidChangeViewState.fire({ viewDescriptor, index });
|
||||
}
|
||||
}
|
||||
|
||||
getSize(id: string): number | undefined {
|
||||
const state = this.viewStates.get(id);
|
||||
|
||||
if (!state) {
|
||||
throw new Error(`Unknown view ${id}`);
|
||||
}
|
||||
|
||||
return state.size;
|
||||
}
|
||||
|
||||
setSize(id: string, size: number): void {
|
||||
const { index, state, viewDescriptor } = this.find(id);
|
||||
if (state.size !== size) {
|
||||
state.size = size;
|
||||
this._onDidChangeViewState.fire({ viewDescriptor, index });
|
||||
}
|
||||
}
|
||||
|
||||
move(from: string, to: string): void {
|
||||
const fromIndex = firstIndex(this.viewDescriptors, v => v.id === from);
|
||||
const toIndex = firstIndex(this.viewDescriptors, v => v.id === to);
|
||||
|
||||
const fromViewDescriptor = this.viewDescriptors[fromIndex];
|
||||
const toViewDescriptor = this.viewDescriptors[toIndex];
|
||||
|
||||
move(this._viewDescriptors, fromIndex, toIndex);
|
||||
|
||||
for (let index = 0; index < this.viewDescriptors.length; index++) {
|
||||
const state = this.viewStates.get(this.viewDescriptors[index].id)!;
|
||||
state.order = index;
|
||||
}
|
||||
|
||||
this._onDidMove.fire({
|
||||
from: { index: fromIndex, viewDescriptor: fromViewDescriptor },
|
||||
to: { index: toIndex, viewDescriptor: toViewDescriptor }
|
||||
});
|
||||
}
|
||||
|
||||
private isViewDescriptorVisible(viewDescriptor: IViewDescriptor): boolean {
|
||||
const viewState = this.viewStates.get(viewDescriptor.id);
|
||||
if (!viewState) {
|
||||
throw new Error(`Unknown view ${viewDescriptor.id}`);
|
||||
}
|
||||
return viewDescriptor.workspace ? !!viewState.visibleWorkspace : !!viewState.visibleGlobal;
|
||||
}
|
||||
|
||||
private find(id: string): { index: number, visibleIndex: number, viewDescriptor: IViewDescriptor, state: IViewState; } {
|
||||
for (let i = 0, visibleIndex = 0; i < this.viewDescriptors.length; i++) {
|
||||
const viewDescriptor = this.viewDescriptors[i];
|
||||
const state = this.viewStates.get(viewDescriptor.id);
|
||||
if (!state) {
|
||||
throw new Error(`View state for ${id} not found`);
|
||||
}
|
||||
|
||||
if (viewDescriptor.id === id) {
|
||||
return { index: i, visibleIndex, viewDescriptor, state };
|
||||
}
|
||||
|
||||
if (viewDescriptor.workspace ? state.visibleWorkspace : state.visibleGlobal) {
|
||||
visibleIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
throw new Error(`view descriptor ${id} not found`);
|
||||
}
|
||||
|
||||
private compareViewDescriptors(a: IViewDescriptor, b: IViewDescriptor): number {
|
||||
if (a.id === b.id) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return (this.getViewOrder(a) - this.getViewOrder(b)) || this.getGroupOrderResult(a, b);
|
||||
}
|
||||
|
||||
private getGroupOrderResult(a: IViewDescriptor, b: IViewDescriptor) {
|
||||
if (!a.group || !b.group) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (a.group === b.group) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return a.group < b.group ? -1 : 1;
|
||||
}
|
||||
|
||||
private getViewOrder(viewDescriptor: IViewDescriptor): number {
|
||||
const viewState = this.viewStates.get(viewDescriptor.id);
|
||||
const viewOrder = viewState && typeof viewState.order === 'number' ? viewState.order : viewDescriptor.order;
|
||||
return typeof viewOrder === 'number' ? viewOrder : Number.MAX_VALUE;
|
||||
}
|
||||
|
||||
private onDidChangeViewDescriptors(viewDescriptors: IViewDescriptor[]): void {
|
||||
for (const viewDescriptor of viewDescriptors) {
|
||||
const viewState = this.viewStates.get(viewDescriptor.id);
|
||||
if (viewState) {
|
||||
// set defaults if not set
|
||||
if (viewDescriptor.workspace) {
|
||||
viewState.visibleWorkspace = isUndefinedOrNull(viewState.visibleWorkspace) ? !viewDescriptor.hideByDefault : viewState.visibleWorkspace;
|
||||
} else {
|
||||
viewState.visibleGlobal = isUndefinedOrNull(viewState.visibleGlobal) ? !viewDescriptor.hideByDefault : viewState.visibleGlobal;
|
||||
}
|
||||
viewState.collapsed = isUndefinedOrNull(viewState.collapsed) ? !!viewDescriptor.collapsed : viewState.collapsed;
|
||||
} else {
|
||||
this.viewStates.set(viewDescriptor.id, {
|
||||
visibleGlobal: !viewDescriptor.hideByDefault,
|
||||
visibleWorkspace: !viewDescriptor.hideByDefault,
|
||||
collapsed: !!viewDescriptor.collapsed
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
viewDescriptors = viewDescriptors.sort(this.compareViewDescriptors.bind(this));
|
||||
|
||||
const toRemove: { index: number, viewDescriptor: IViewDescriptor; }[] = [];
|
||||
for (let index = 0; index < this._viewDescriptors.length; index++) {
|
||||
const previousViewDescriptor = this._viewDescriptors[index];
|
||||
if (this.isViewDescriptorVisible(previousViewDescriptor) && viewDescriptors.every(viewDescriptor => viewDescriptor.id !== previousViewDescriptor.id)) {
|
||||
const { visibleIndex } = this.find(previousViewDescriptor.id);
|
||||
toRemove.push({ index: visibleIndex, viewDescriptor: previousViewDescriptor });
|
||||
}
|
||||
}
|
||||
|
||||
const previous = this._viewDescriptors;
|
||||
this._viewDescriptors = viewDescriptors.slice(0);
|
||||
|
||||
const toAdd: { index: number, viewDescriptor: IViewDescriptor, size?: number, collapsed: boolean; }[] = [];
|
||||
for (let i = 0; i < this._viewDescriptors.length; i++) {
|
||||
const viewDescriptor = this._viewDescriptors[i];
|
||||
if (this.isViewDescriptorVisible(viewDescriptor) && previous.every(previousViewDescriptor => previousViewDescriptor.id !== viewDescriptor.id)) {
|
||||
const { visibleIndex, state } = this.find(viewDescriptor.id);
|
||||
toAdd.push({ index: visibleIndex, viewDescriptor, size: state.size, collapsed: !!state.collapsed });
|
||||
}
|
||||
}
|
||||
|
||||
if (toRemove.length) {
|
||||
this._onDidRemove.fire(toRemove);
|
||||
}
|
||||
|
||||
if (toAdd.length) {
|
||||
this._onDidAdd.fire(toAdd);
|
||||
}
|
||||
|
||||
this._onDidChangeActiveViews.fire(this.viewDescriptors);
|
||||
}
|
||||
}
|
||||
|
||||
interface IStoredWorkspaceViewState {
|
||||
collapsed: boolean;
|
||||
isHidden: boolean;
|
||||
size?: number;
|
||||
order?: number;
|
||||
}
|
||||
|
||||
interface IStoredGlobalViewState {
|
||||
id: string;
|
||||
isHidden: boolean;
|
||||
order?: number;
|
||||
}
|
||||
|
||||
export class PersistentViewsModel extends ViewsModel {
|
||||
|
||||
private readonly workspaceViewsStateStorageId: string;
|
||||
private readonly globalViewsStateStorageId: string;
|
||||
|
||||
private storageService: IStorageService;
|
||||
|
||||
constructor(
|
||||
viewletStateStorageId: string,
|
||||
viewDescriptorCollection: ViewDescriptorsModel,
|
||||
@IStorageService storageService: IStorageService,
|
||||
@IStorageKeysSyncRegistryService storageKeysSyncRegistryService: IStorageKeysSyncRegistryService
|
||||
) {
|
||||
const globalViewsStateStorageId = `${viewletStateStorageId}.hidden`;
|
||||
storageKeysSyncRegistryService.registerStorageKey({ key: globalViewsStateStorageId, version: 1 });
|
||||
const viewStates = PersistentViewsModel.loadViewsStates(viewletStateStorageId, globalViewsStateStorageId, storageService);
|
||||
|
||||
super(viewDescriptorCollection, viewStates);
|
||||
|
||||
this.storageService = storageService;
|
||||
this.workspaceViewsStateStorageId = viewletStateStorageId;
|
||||
this.globalViewsStateStorageId = globalViewsStateStorageId;
|
||||
|
||||
this._register(Event.any(
|
||||
this.onDidAdd,
|
||||
this.onDidRemove,
|
||||
Event.map(this.onDidMove, ({ from, to }) => [from, to]),
|
||||
Event.map(this.onDidChangeViewState, viewDescriptorRef => [viewDescriptorRef]))
|
||||
(viewDescriptorRefs => this.saveViewsStates()));
|
||||
|
||||
this._globalViewsStatesValue = this.getStoredGlobalViewsStatesValue();
|
||||
this._register(this.storageService.onDidChangeStorage(e => this.onDidStorageChange(e)));
|
||||
}
|
||||
|
||||
private onDidStorageChange(e: IWorkspaceStorageChangeEvent): void {
|
||||
if (e.key === this.globalViewsStateStorageId && e.scope === StorageScope.GLOBAL
|
||||
&& this.globalViewsStatesValue !== this.getStoredGlobalViewsStatesValue() /* This checks if current window changed the value or not */) {
|
||||
this._globalViewsStatesValue = undefined;
|
||||
const storedViewsVisibilityStates = PersistentViewsModel.loadGlobalViewsState(this.globalViewsStateStorageId, this.storageService, StorageScope.GLOBAL);
|
||||
const changedViews: { id: string, visible: boolean }[] = [];
|
||||
for (const [id, state] of storedViewsVisibilityStates) {
|
||||
const viewState = this.viewStates.get(id);
|
||||
if (viewState) {
|
||||
if (viewState.visibleGlobal !== !state.isHidden) {
|
||||
changedViews.push({ id, visible: !state.isHidden });
|
||||
}
|
||||
}
|
||||
}
|
||||
if (changedViews.length) {
|
||||
this.doSetVisible(changedViews);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private saveViewsStates(): void {
|
||||
this.saveWorkspaceViewsStates();
|
||||
this.saveGlobalViewsStates();
|
||||
}
|
||||
|
||||
private saveWorkspaceViewsStates(): void {
|
||||
const storedViewsStates: { [id: string]: IStoredWorkspaceViewState; } = JSON.parse(this.storageService.get(this.workspaceViewsStateStorageId, StorageScope.WORKSPACE, '{}'));
|
||||
for (const viewDescriptor of this.viewDescriptors) {
|
||||
const viewState = this.viewStates.get(viewDescriptor.id);
|
||||
if (viewState) {
|
||||
storedViewsStates[viewDescriptor.id] = {
|
||||
collapsed: !!viewState.collapsed,
|
||||
isHidden: !viewState.visibleWorkspace,
|
||||
size: viewState.size,
|
||||
order: viewDescriptor.workspace && viewState ? viewState.order : undefined
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
if (Object.keys(storedViewsStates).length > 0) {
|
||||
this.storageService.store(this.workspaceViewsStateStorageId, JSON.stringify(storedViewsStates), StorageScope.WORKSPACE);
|
||||
} else {
|
||||
this.storageService.remove(this.workspaceViewsStateStorageId, StorageScope.WORKSPACE);
|
||||
}
|
||||
}
|
||||
|
||||
private saveGlobalViewsStates(): void {
|
||||
const storedViewsVisibilityStates = PersistentViewsModel.loadGlobalViewsState(this.globalViewsStateStorageId, this.storageService, StorageScope.GLOBAL);
|
||||
for (const viewDescriptor of this.viewDescriptors) {
|
||||
const viewState = this.viewStates.get(viewDescriptor.id);
|
||||
storedViewsVisibilityStates.set(viewDescriptor.id, {
|
||||
id: viewDescriptor.id,
|
||||
isHidden: viewState && viewDescriptor.canToggleVisibility ? !viewState.visibleGlobal : false,
|
||||
order: !viewDescriptor.workspace && viewState ? viewState.order : undefined
|
||||
});
|
||||
}
|
||||
this.globalViewsStatesValue = JSON.stringify(values(storedViewsVisibilityStates));
|
||||
}
|
||||
|
||||
private _globalViewsStatesValue: string | undefined;
|
||||
private get globalViewsStatesValue(): string {
|
||||
if (!this._globalViewsStatesValue) {
|
||||
this._globalViewsStatesValue = this.getStoredGlobalViewsStatesValue();
|
||||
}
|
||||
|
||||
return this._globalViewsStatesValue;
|
||||
}
|
||||
|
||||
private set globalViewsStatesValue(globalViewsStatesValue: string) {
|
||||
if (this.globalViewsStatesValue !== globalViewsStatesValue) {
|
||||
this._globalViewsStatesValue = globalViewsStatesValue;
|
||||
this.setStoredGlobalViewsStatesValue(globalViewsStatesValue);
|
||||
}
|
||||
}
|
||||
|
||||
private getStoredGlobalViewsStatesValue(): string {
|
||||
return this.storageService.get(this.globalViewsStateStorageId, StorageScope.GLOBAL, '[]');
|
||||
}
|
||||
|
||||
private setStoredGlobalViewsStatesValue(value: string): void {
|
||||
this.storageService.store(this.globalViewsStateStorageId, value, StorageScope.GLOBAL);
|
||||
}
|
||||
|
||||
private static loadViewsStates(workspaceViewsStateStorageId: string, globalViewsStateStorageId: string, storageService: IStorageService): Map<string, IViewState> {
|
||||
const viewStates = new Map<string, IViewState>();
|
||||
const workspaceViewsStates = <{ [id: string]: IStoredWorkspaceViewState; }>JSON.parse(storageService.get(workspaceViewsStateStorageId, StorageScope.WORKSPACE, '{}'));
|
||||
for (const id of Object.keys(workspaceViewsStates)) {
|
||||
const workspaceViewState = workspaceViewsStates[id];
|
||||
viewStates.set(id, {
|
||||
visibleGlobal: undefined,
|
||||
visibleWorkspace: isUndefined(workspaceViewState.isHidden) ? undefined : !workspaceViewState.isHidden,
|
||||
collapsed: workspaceViewState.collapsed,
|
||||
order: workspaceViewState.order,
|
||||
size: workspaceViewState.size
|
||||
});
|
||||
}
|
||||
|
||||
// Migrate to `viewletStateStorageId`
|
||||
const workspaceVisibilityStates = this.loadGlobalViewsState(globalViewsStateStorageId, storageService, StorageScope.WORKSPACE);
|
||||
if (workspaceVisibilityStates.size > 0) {
|
||||
for (const { id, isHidden } of values(workspaceVisibilityStates)) {
|
||||
let viewState = viewStates.get(id);
|
||||
// Not migrated to `viewletStateStorageId`
|
||||
if (viewState) {
|
||||
if (isUndefined(viewState.visibleWorkspace)) {
|
||||
viewState.visibleWorkspace = !isHidden;
|
||||
}
|
||||
} else {
|
||||
viewStates.set(id, {
|
||||
collapsed: undefined,
|
||||
visibleGlobal: undefined,
|
||||
visibleWorkspace: !isHidden,
|
||||
});
|
||||
}
|
||||
}
|
||||
storageService.remove(globalViewsStateStorageId, StorageScope.WORKSPACE);
|
||||
}
|
||||
|
||||
const globalViewsStates = this.loadGlobalViewsState(globalViewsStateStorageId, storageService, StorageScope.GLOBAL);
|
||||
for (const { id, isHidden, order } of values(globalViewsStates)) {
|
||||
let viewState = viewStates.get(id);
|
||||
if (viewState) {
|
||||
viewState.visibleGlobal = !isHidden;
|
||||
if (!isUndefined(order)) {
|
||||
viewState.order = order;
|
||||
}
|
||||
} else {
|
||||
viewStates.set(id, {
|
||||
visibleGlobal: !isHidden,
|
||||
order,
|
||||
collapsed: undefined,
|
||||
visibleWorkspace: undefined,
|
||||
});
|
||||
}
|
||||
}
|
||||
return viewStates;
|
||||
}
|
||||
|
||||
private static loadGlobalViewsState(globalViewsStateStorageId: string, storageService: IStorageService, scope: StorageScope): Map<string, IStoredGlobalViewState> {
|
||||
const storedValue = <Array<string | IStoredGlobalViewState>>JSON.parse(storageService.get(globalViewsStateStorageId, scope, '[]'));
|
||||
let hasDuplicates = false;
|
||||
const storedGlobalViewsState = storedValue.reduce((result, storedState) => {
|
||||
if (typeof storedState === 'string' /* migration */) {
|
||||
hasDuplicates = hasDuplicates || result.has(storedState);
|
||||
result.set(storedState, { id: storedState, isHidden: true });
|
||||
} else {
|
||||
hasDuplicates = hasDuplicates || result.has(storedState.id);
|
||||
result.set(storedState.id, storedState);
|
||||
}
|
||||
return result;
|
||||
}, new Map<string, IStoredGlobalViewState>());
|
||||
|
||||
if (hasDuplicates) {
|
||||
storageService.store(globalViewsStateStorageId, JSON.stringify(values(storedGlobalViewsState)), scope);
|
||||
}
|
||||
|
||||
return storedGlobalViewsState;
|
||||
}
|
||||
}
|
||||
@@ -11,6 +11,8 @@ import { TestInstantiationService } from 'vs/platform/instantiation/test/common/
|
||||
import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
|
||||
import { ViewDescriptorService } from 'vs/workbench/services/views/browser/viewDescriptorService';
|
||||
import { assertIsDefined } from 'vs/base/common/types';
|
||||
import { ContextKeyService } from 'vs/platform/contextkey/browser/contextKeyService';
|
||||
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
||||
|
||||
const ViewsRegistry = Registry.as<IViewsRegistry>(ViewContainerExtensions.ViewsRegistry);
|
||||
const sidebarContainer = Registry.as<IViewContainersRegistry>(ViewContainerExtensions.ViewContainersRegistry).registerViewContainer({ id: 'testSidebar', name: 'test', ctorDescriptor: new SyncDescriptor(<any>{}) }, ViewContainerLocation.Sidebar);
|
||||
@@ -22,6 +24,7 @@ suite('ViewDescriptorService', () => {
|
||||
|
||||
setup(() => {
|
||||
const instantiationService: TestInstantiationService = <TestInstantiationService>workbenchInstantiationService();
|
||||
instantiationService.stub(IContextKeyService, instantiationService.createInstance(ContextKeyService));
|
||||
viewDescriptorService = instantiationService.createInstance(ViewDescriptorService);
|
||||
});
|
||||
|
||||
@@ -31,8 +34,8 @@ suite('ViewDescriptorService', () => {
|
||||
});
|
||||
|
||||
test('Empty Containers', function () {
|
||||
const sidebarViews = viewDescriptorService.getViewDescriptors(sidebarContainer);
|
||||
const panelViews = viewDescriptorService.getViewDescriptors(panelContainer);
|
||||
const sidebarViews = viewDescriptorService.getViewContainerModel(sidebarContainer);
|
||||
const panelViews = viewDescriptorService.getViewContainerModel(panelContainer);
|
||||
assert.equal(sidebarViews.allViewDescriptors.length, 0, 'The sidebar container should have no views yet.');
|
||||
assert.equal(panelViews.allViewDescriptors.length, 0, 'The panel container should have no views yet.');
|
||||
});
|
||||
@@ -64,8 +67,8 @@ suite('ViewDescriptorService', () => {
|
||||
ViewsRegistry.registerViews(viewDescriptors.slice(2), panelContainer);
|
||||
|
||||
|
||||
let sidebarViews = viewDescriptorService.getViewDescriptors(sidebarContainer);
|
||||
let panelViews = viewDescriptorService.getViewDescriptors(panelContainer);
|
||||
let sidebarViews = viewDescriptorService.getViewContainerModel(sidebarContainer);
|
||||
let panelViews = viewDescriptorService.getViewContainerModel(panelContainer);
|
||||
|
||||
assert.equal(sidebarViews.activeViewDescriptors.length, 2, 'Sidebar should have 2 views');
|
||||
assert.equal(panelViews.activeViewDescriptors.length, 1, 'Panel should have 1 view');
|
||||
@@ -74,8 +77,8 @@ suite('ViewDescriptorService', () => {
|
||||
ViewsRegistry.deregisterViews(viewDescriptors.slice(2), panelContainer);
|
||||
|
||||
|
||||
sidebarViews = viewDescriptorService.getViewDescriptors(sidebarContainer);
|
||||
panelViews = viewDescriptorService.getViewDescriptors(panelContainer);
|
||||
sidebarViews = viewDescriptorService.getViewContainerModel(sidebarContainer);
|
||||
panelViews = viewDescriptorService.getViewContainerModel(panelContainer);
|
||||
|
||||
assert.equal(sidebarViews.activeViewDescriptors.length, 0, 'Sidebar should have no views');
|
||||
assert.equal(panelViews.activeViewDescriptors.length, 0, 'Panel should have no views');
|
||||
@@ -109,8 +112,8 @@ suite('ViewDescriptorService', () => {
|
||||
viewDescriptorService.moveViewsToContainer(viewDescriptors.slice(2), sidebarContainer);
|
||||
viewDescriptorService.moveViewsToContainer(viewDescriptors.slice(0, 2), panelContainer);
|
||||
|
||||
let sidebarViews = viewDescriptorService.getViewDescriptors(sidebarContainer);
|
||||
let panelViews = viewDescriptorService.getViewDescriptors(panelContainer);
|
||||
let sidebarViews = viewDescriptorService.getViewContainerModel(sidebarContainer);
|
||||
let panelViews = viewDescriptorService.getViewContainerModel(panelContainer);
|
||||
|
||||
assert.equal(sidebarViews.activeViewDescriptors.length, 1, 'Sidebar should have 2 views');
|
||||
assert.equal(panelViews.activeViewDescriptors.length, 2, 'Panel should have 1 view');
|
||||
@@ -148,8 +151,8 @@ suite('ViewDescriptorService', () => {
|
||||
viewDescriptorService.moveViewToLocation(viewDescriptors[0], ViewContainerLocation.Panel);
|
||||
viewDescriptorService.moveViewToLocation(viewDescriptors[2], ViewContainerLocation.Sidebar);
|
||||
|
||||
let sidebarViews = viewDescriptorService.getViewDescriptors(sidebarContainer);
|
||||
let panelViews = viewDescriptorService.getViewDescriptors(panelContainer);
|
||||
let sidebarViews = viewDescriptorService.getViewContainerModel(sidebarContainer);
|
||||
let panelViews = viewDescriptorService.getViewContainerModel(panelContainer);
|
||||
|
||||
assert.equal(sidebarViews.activeViewDescriptors.length, 1, 'Sidebar container should have 1 view');
|
||||
assert.equal(panelViews.activeViewDescriptors.length, 0, 'Panel container should have no views');
|
||||
@@ -169,8 +172,8 @@ suite('ViewDescriptorService', () => {
|
||||
viewDescriptorService.moveViewToLocation(viewDescriptors[0], ViewContainerLocation.Sidebar);
|
||||
viewDescriptorService.moveViewToLocation(viewDescriptors[2], ViewContainerLocation.Panel);
|
||||
|
||||
sidebarViews = viewDescriptorService.getViewDescriptors(sidebarContainer);
|
||||
panelViews = viewDescriptorService.getViewDescriptors(panelContainer);
|
||||
sidebarViews = viewDescriptorService.getViewContainerModel(sidebarContainer);
|
||||
panelViews = viewDescriptorService.getViewContainerModel(panelContainer);
|
||||
|
||||
assert.equal(sidebarViews.activeViewDescriptors.length, 1, 'Sidebar should have 2 views');
|
||||
assert.equal(panelViews.activeViewDescriptors.length, 0, 'Panel should have 1 view');
|
||||
|
||||
@@ -5,25 +5,31 @@
|
||||
|
||||
import * as assert from 'assert';
|
||||
import * as sinon from 'sinon';
|
||||
import { IViewDescriptor } from 'vs/workbench/common/views';
|
||||
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
|
||||
import { IViewsRegistry, IViewDescriptor, IViewContainersRegistry, Extensions as ViewContainerExtensions, ViewContainerLocation, IViewContainerModel, IViewDescriptorService, ViewContainer } from 'vs/workbench/common/views';
|
||||
import { IDisposable, dispose, DisposableStore } from 'vs/base/common/lifecycle';
|
||||
import { move } from 'vs/base/common/arrays';
|
||||
import { workbenchInstantiationService } from 'vs/workbench/test/browser/workbenchTestServices';
|
||||
import { ContextKeyExpr, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock';
|
||||
import { ContextKeyService } from 'vs/platform/contextkey/browser/contextKeyService';
|
||||
import { IViewState, ViewDescriptorsModel, ViewsModel } from 'vs/workbench/services/views/common/viewsModel';
|
||||
import { ViewDescriptorService } from 'vs/workbench/services/views/browser/viewDescriptorService';
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
|
||||
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
|
||||
|
||||
const ViewContainerRegistry = Registry.as<IViewContainersRegistry>(ViewContainerExtensions.ViewContainersRegistry);
|
||||
const ViewsRegistry = Registry.as<IViewsRegistry>(ViewContainerExtensions.ViewsRegistry);
|
||||
|
||||
class ViewDescriptorSequence {
|
||||
|
||||
readonly elements: IViewDescriptor[];
|
||||
private disposables: IDisposable[] = [];
|
||||
|
||||
constructor(model: ViewsModel) {
|
||||
constructor(model: IViewContainerModel) {
|
||||
this.elements = [...model.visibleViewDescriptors];
|
||||
model.onDidAdd(added => added.forEach(({ viewDescriptor, index }) => this.elements.splice(index, 0, viewDescriptor)), null, this.disposables);
|
||||
model.onDidRemove(removed => removed.sort((a, b) => b.index - a.index).forEach(({ index }) => this.elements.splice(index, 1)), null, this.disposables);
|
||||
model.onDidMove(({ from, to }) => move(this.elements, from.index, to.index), null, this.disposables);
|
||||
model.onDidAddVisibleViewDescriptors(added => added.forEach(({ viewDescriptor, index }) => this.elements.splice(index, 0, viewDescriptor)), null, this.disposables);
|
||||
model.onDidRemoveVisibleViewDescriptors(removed => removed.sort((a, b) => b.index - a.index).forEach(({ index }) => this.elements.splice(index, 1)), null, this.disposables);
|
||||
model.onDidMoveVisibleViewDescriptors(({ from, to }) => move(this.elements, from.index, to.index), null, this.disposables);
|
||||
}
|
||||
|
||||
dispose() {
|
||||
@@ -31,29 +37,42 @@ class ViewDescriptorSequence {
|
||||
}
|
||||
}
|
||||
|
||||
suite('ContributableViewsModel', () => {
|
||||
suite('ViewContainerModel', () => {
|
||||
|
||||
let container: ViewContainer;
|
||||
let disposableStore: DisposableStore;
|
||||
let contextKeyService: IContextKeyService;
|
||||
let viewDescriptorService: IViewDescriptorService;
|
||||
let storageService: IStorageService;
|
||||
|
||||
setup(() => {
|
||||
disposableStore = new DisposableStore();
|
||||
const instantiationService: TestInstantiationService = <TestInstantiationService>workbenchInstantiationService();
|
||||
contextKeyService = instantiationService.createInstance(ContextKeyService);
|
||||
instantiationService.stub(IContextKeyService, contextKeyService);
|
||||
storageService = instantiationService.get(IStorageService);
|
||||
viewDescriptorService = instantiationService.createInstance(ViewDescriptorService);
|
||||
});
|
||||
|
||||
teardown(() => {
|
||||
disposableStore.dispose();
|
||||
ViewsRegistry.deregisterViews(ViewsRegistry.getViews(container), container);
|
||||
ViewContainerRegistry.deregisterViewContainer(container);
|
||||
});
|
||||
|
||||
test('empty model', function () {
|
||||
const viewsDescriptorsModel = new ViewDescriptorsModel(contextKeyService);
|
||||
const model = new ViewsModel(viewsDescriptorsModel);
|
||||
assert.equal(model.visibleViewDescriptors.length, 0);
|
||||
container = ViewContainerRegistry.registerViewContainer({ id: 'test', name: 'test', ctorDescriptor: new SyncDescriptor(<any>{}) }, ViewContainerLocation.Sidebar);
|
||||
const testObject = viewDescriptorService.getViewContainerModel(container);
|
||||
assert.equal(testObject.visibleViewDescriptors.length, 0);
|
||||
});
|
||||
|
||||
test('register/unregister', () => {
|
||||
const viewsDescriptorsModel = new ViewDescriptorsModel(contextKeyService);
|
||||
const model = new ViewsModel(viewsDescriptorsModel);
|
||||
const seq = new ViewDescriptorSequence(model);
|
||||
container = ViewContainerRegistry.registerViewContainer({ id: 'test', name: 'test', ctorDescriptor: new SyncDescriptor(<any>{}) }, ViewContainerLocation.Sidebar);
|
||||
const testObject = viewDescriptorService.getViewContainerModel(container);
|
||||
const target = disposableStore.add(new ViewDescriptorSequence(testObject));
|
||||
|
||||
assert.equal(model.visibleViewDescriptors.length, 0);
|
||||
assert.equal(seq.elements.length, 0);
|
||||
assert.equal(testObject.visibleViewDescriptors.length, 0);
|
||||
assert.equal(target.elements.length, 0);
|
||||
|
||||
const viewDescriptor: IViewDescriptor = {
|
||||
id: 'view1',
|
||||
@@ -61,26 +80,25 @@ suite('ContributableViewsModel', () => {
|
||||
name: 'Test View 1'
|
||||
};
|
||||
|
||||
viewsDescriptorsModel.addViews([viewDescriptor]);
|
||||
ViewsRegistry.registerViews([viewDescriptor], container);
|
||||
|
||||
assert.equal(model.visibleViewDescriptors.length, 1);
|
||||
assert.equal(seq.elements.length, 1);
|
||||
assert.deepEqual(model.visibleViewDescriptors[0], viewDescriptor);
|
||||
assert.deepEqual(seq.elements[0], viewDescriptor);
|
||||
assert.equal(testObject.visibleViewDescriptors.length, 1);
|
||||
assert.equal(target.elements.length, 1);
|
||||
assert.deepEqual(testObject.visibleViewDescriptors[0], viewDescriptor);
|
||||
assert.deepEqual(target.elements[0], viewDescriptor);
|
||||
|
||||
viewsDescriptorsModel.removeViews([viewDescriptor]);
|
||||
ViewsRegistry.deregisterViews([viewDescriptor], container);
|
||||
|
||||
assert.equal(model.visibleViewDescriptors.length, 0);
|
||||
assert.equal(seq.elements.length, 0);
|
||||
assert.equal(testObject.visibleViewDescriptors.length, 0);
|
||||
assert.equal(target.elements.length, 0);
|
||||
});
|
||||
|
||||
test('when contexts', async function () {
|
||||
const viewsDescriptorsModel = new ViewDescriptorsModel(contextKeyService);
|
||||
const model = new ViewsModel(viewsDescriptorsModel);
|
||||
const seq = new ViewDescriptorSequence(model);
|
||||
|
||||
assert.equal(model.visibleViewDescriptors.length, 0);
|
||||
assert.equal(seq.elements.length, 0);
|
||||
container = ViewContainerRegistry.registerViewContainer({ id: 'test', name: 'test', ctorDescriptor: new SyncDescriptor(<any>{}) }, ViewContainerLocation.Sidebar);
|
||||
const testObject = viewDescriptorService.getViewContainerModel(container);
|
||||
const target = disposableStore.add(new ViewDescriptorSequence(testObject));
|
||||
assert.equal(testObject.visibleViewDescriptors.length, 0);
|
||||
assert.equal(target.elements.length, 0);
|
||||
|
||||
const viewDescriptor: IViewDescriptor = {
|
||||
id: 'view1',
|
||||
@@ -89,169 +107,164 @@ suite('ContributableViewsModel', () => {
|
||||
when: ContextKeyExpr.equals('showview1', true)
|
||||
};
|
||||
|
||||
viewsDescriptorsModel.addViews([viewDescriptor]);
|
||||
assert.equal(model.visibleViewDescriptors.length, 0, 'view should not appear since context isnt in');
|
||||
assert.equal(seq.elements.length, 0);
|
||||
ViewsRegistry.registerViews([viewDescriptor], container);
|
||||
assert.equal(testObject.visibleViewDescriptors.length, 0, 'view should not appear since context isnt in');
|
||||
assert.equal(target.elements.length, 0);
|
||||
|
||||
const key = contextKeyService.createKey('showview1', false);
|
||||
assert.equal(model.visibleViewDescriptors.length, 0, 'view should still not appear since showview1 isnt true');
|
||||
assert.equal(seq.elements.length, 0);
|
||||
assert.equal(testObject.visibleViewDescriptors.length, 0, 'view should still not appear since showview1 isnt true');
|
||||
assert.equal(target.elements.length, 0);
|
||||
|
||||
key.set(true);
|
||||
await new Promise(c => setTimeout(c, 30));
|
||||
assert.equal(model.visibleViewDescriptors.length, 1, 'view should appear');
|
||||
assert.equal(seq.elements.length, 1);
|
||||
assert.deepEqual(model.visibleViewDescriptors[0], viewDescriptor);
|
||||
assert.equal(seq.elements[0], viewDescriptor);
|
||||
assert.equal(testObject.visibleViewDescriptors.length, 1, 'view should appear');
|
||||
assert.equal(target.elements.length, 1);
|
||||
assert.deepEqual(testObject.visibleViewDescriptors[0], viewDescriptor);
|
||||
assert.equal(target.elements[0], viewDescriptor);
|
||||
|
||||
key.set(false);
|
||||
await new Promise(c => setTimeout(c, 30));
|
||||
assert.equal(model.visibleViewDescriptors.length, 0, 'view should disappear');
|
||||
assert.equal(seq.elements.length, 0);
|
||||
assert.equal(testObject.visibleViewDescriptors.length, 0, 'view should disappear');
|
||||
assert.equal(target.elements.length, 0);
|
||||
|
||||
viewsDescriptorsModel.removeViews([viewDescriptor]);
|
||||
assert.equal(model.visibleViewDescriptors.length, 0, 'view should not be there anymore');
|
||||
assert.equal(seq.elements.length, 0);
|
||||
ViewsRegistry.deregisterViews([viewDescriptor], container);
|
||||
assert.equal(testObject.visibleViewDescriptors.length, 0, 'view should not be there anymore');
|
||||
assert.equal(target.elements.length, 0);
|
||||
|
||||
key.set(true);
|
||||
await new Promise(c => setTimeout(c, 30));
|
||||
assert.equal(model.visibleViewDescriptors.length, 0, 'view should not be there anymore');
|
||||
assert.equal(seq.elements.length, 0);
|
||||
assert.equal(testObject.visibleViewDescriptors.length, 0, 'view should not be there anymore');
|
||||
assert.equal(target.elements.length, 0);
|
||||
});
|
||||
|
||||
test('when contexts - multiple', async function () {
|
||||
const viewsDescriptorsModel = new ViewDescriptorsModel(contextKeyService);
|
||||
const model = new ViewsModel(viewsDescriptorsModel);
|
||||
const seq = new ViewDescriptorSequence(model);
|
||||
|
||||
container = ViewContainerRegistry.registerViewContainer({ id: 'test', name: 'test', ctorDescriptor: new SyncDescriptor(<any>{}) }, ViewContainerLocation.Sidebar);
|
||||
const testObject = viewDescriptorService.getViewContainerModel(container);
|
||||
const target = disposableStore.add(new ViewDescriptorSequence(testObject));
|
||||
const view1: IViewDescriptor = { id: 'view1', ctorDescriptor: null!, name: 'Test View 1' };
|
||||
const view2: IViewDescriptor = { id: 'view2', ctorDescriptor: null!, name: 'Test View 2', when: ContextKeyExpr.equals('showview2', true) };
|
||||
|
||||
viewsDescriptorsModel.addViews([view1, view2]);
|
||||
assert.deepEqual(model.visibleViewDescriptors, [view1], 'only view1 should be visible');
|
||||
assert.deepEqual(seq.elements, [view1], 'only view1 should be visible');
|
||||
ViewsRegistry.registerViews([view1, view2], container);
|
||||
assert.deepEqual(testObject.visibleViewDescriptors, [view1], 'only view1 should be visible');
|
||||
assert.deepEqual(target.elements, [view1], 'only view1 should be visible');
|
||||
|
||||
const key = contextKeyService.createKey('showview2', false);
|
||||
assert.deepEqual(model.visibleViewDescriptors, [view1], 'still only view1 should be visible');
|
||||
assert.deepEqual(seq.elements, [view1], 'still only view1 should be visible');
|
||||
assert.deepEqual(testObject.visibleViewDescriptors, [view1], 'still only view1 should be visible');
|
||||
assert.deepEqual(target.elements, [view1], 'still only view1 should be visible');
|
||||
|
||||
key.set(true);
|
||||
await new Promise(c => setTimeout(c, 30));
|
||||
assert.deepEqual(model.visibleViewDescriptors, [view1, view2], 'both views should be visible');
|
||||
assert.deepEqual(seq.elements, [view1, view2], 'both views should be visible');
|
||||
assert.deepEqual(testObject.visibleViewDescriptors, [view1, view2], 'both views should be visible');
|
||||
assert.deepEqual(target.elements, [view1, view2], 'both views should be visible');
|
||||
|
||||
viewsDescriptorsModel.removeViews([view1, view2]);
|
||||
ViewsRegistry.deregisterViews([view1, view2], container);
|
||||
});
|
||||
|
||||
test('when contexts - multiple 2', async function () {
|
||||
const viewsDescriptorsModel = new ViewDescriptorsModel(contextKeyService);
|
||||
const model = new ViewsModel(viewsDescriptorsModel);
|
||||
const seq = new ViewDescriptorSequence(model);
|
||||
|
||||
container = ViewContainerRegistry.registerViewContainer({ id: 'test', name: 'test', ctorDescriptor: new SyncDescriptor(<any>{}) }, ViewContainerLocation.Sidebar);
|
||||
const testObject = viewDescriptorService.getViewContainerModel(container);
|
||||
const target = disposableStore.add(new ViewDescriptorSequence(testObject));
|
||||
const view1: IViewDescriptor = { id: 'view1', ctorDescriptor: null!, name: 'Test View 1', when: ContextKeyExpr.equals('showview1', true) };
|
||||
const view2: IViewDescriptor = { id: 'view2', ctorDescriptor: null!, name: 'Test View 2' };
|
||||
|
||||
viewsDescriptorsModel.addViews([view1, view2]);
|
||||
assert.deepEqual(model.visibleViewDescriptors, [view2], 'only view2 should be visible');
|
||||
assert.deepEqual(seq.elements, [view2], 'only view2 should be visible');
|
||||
ViewsRegistry.registerViews([view1, view2], container);
|
||||
assert.deepEqual(testObject.visibleViewDescriptors, [view2], 'only view2 should be visible');
|
||||
assert.deepEqual(target.elements, [view2], 'only view2 should be visible');
|
||||
|
||||
const key = contextKeyService.createKey('showview1', false);
|
||||
assert.deepEqual(model.visibleViewDescriptors, [view2], 'still only view2 should be visible');
|
||||
assert.deepEqual(seq.elements, [view2], 'still only view2 should be visible');
|
||||
assert.deepEqual(testObject.visibleViewDescriptors, [view2], 'still only view2 should be visible');
|
||||
assert.deepEqual(target.elements, [view2], 'still only view2 should be visible');
|
||||
|
||||
key.set(true);
|
||||
await new Promise(c => setTimeout(c, 30));
|
||||
assert.deepEqual(model.visibleViewDescriptors, [view1, view2], 'both views should be visible');
|
||||
assert.deepEqual(seq.elements, [view1, view2], 'both views should be visible');
|
||||
assert.deepEqual(testObject.visibleViewDescriptors, [view1, view2], 'both views should be visible');
|
||||
assert.deepEqual(target.elements, [view1, view2], 'both views should be visible');
|
||||
|
||||
viewsDescriptorsModel.removeViews([view1, view2]);
|
||||
ViewsRegistry.deregisterViews([view1, view2], container);
|
||||
});
|
||||
|
||||
test('setVisible', () => {
|
||||
const viewsDescriptorsModel = new ViewDescriptorsModel(contextKeyService);
|
||||
const model = new ViewsModel(viewsDescriptorsModel);
|
||||
const seq = new ViewDescriptorSequence(model);
|
||||
|
||||
container = ViewContainerRegistry.registerViewContainer({ id: 'test', name: 'test', ctorDescriptor: new SyncDescriptor(<any>{}) }, ViewContainerLocation.Sidebar);
|
||||
const testObject = viewDescriptorService.getViewContainerModel(container);
|
||||
const target = disposableStore.add(new ViewDescriptorSequence(testObject));
|
||||
const view1: IViewDescriptor = { id: 'view1', ctorDescriptor: null!, name: 'Test View 1', canToggleVisibility: true };
|
||||
const view2: IViewDescriptor = { id: 'view2', ctorDescriptor: null!, name: 'Test View 2', canToggleVisibility: true };
|
||||
const view3: IViewDescriptor = { id: 'view3', ctorDescriptor: null!, name: 'Test View 3', canToggleVisibility: true };
|
||||
|
||||
viewsDescriptorsModel.addViews([view1, view2, view3]);
|
||||
assert.deepEqual(model.visibleViewDescriptors, [view1, view2, view3]);
|
||||
assert.deepEqual(seq.elements, [view1, view2, view3]);
|
||||
ViewsRegistry.registerViews([view1, view2, view3], container);
|
||||
assert.deepEqual(testObject.visibleViewDescriptors, [view1, view2, view3]);
|
||||
assert.deepEqual(target.elements, [view1, view2, view3]);
|
||||
|
||||
model.setVisible('view2', true);
|
||||
assert.deepEqual(model.visibleViewDescriptors, [view1, view2, view3], 'nothing should happen');
|
||||
assert.deepEqual(seq.elements, [view1, view2, view3]);
|
||||
testObject.setVisible('view2', true);
|
||||
assert.deepEqual(testObject.visibleViewDescriptors, [view1, view2, view3], 'nothing should happen');
|
||||
assert.deepEqual(target.elements, [view1, view2, view3]);
|
||||
|
||||
model.setVisible('view2', false);
|
||||
assert.deepEqual(model.visibleViewDescriptors, [view1, view3], 'view2 should hide');
|
||||
assert.deepEqual(seq.elements, [view1, view3]);
|
||||
testObject.setVisible('view2', false);
|
||||
assert.deepEqual(testObject.visibleViewDescriptors, [view1, view3], 'view2 should hide');
|
||||
assert.deepEqual(target.elements, [view1, view3]);
|
||||
|
||||
model.setVisible('view1', false);
|
||||
assert.deepEqual(model.visibleViewDescriptors, [view3], 'view1 should hide');
|
||||
assert.deepEqual(seq.elements, [view3]);
|
||||
testObject.setVisible('view1', false);
|
||||
assert.deepEqual(testObject.visibleViewDescriptors, [view3], 'view1 should hide');
|
||||
assert.deepEqual(target.elements, [view3]);
|
||||
|
||||
model.setVisible('view3', false);
|
||||
assert.deepEqual(model.visibleViewDescriptors, [], 'view3 shoud hide');
|
||||
assert.deepEqual(seq.elements, []);
|
||||
testObject.setVisible('view3', false);
|
||||
assert.deepEqual(testObject.visibleViewDescriptors, [], 'view3 shoud hide');
|
||||
assert.deepEqual(target.elements, []);
|
||||
|
||||
model.setVisible('view1', true);
|
||||
assert.deepEqual(model.visibleViewDescriptors, [view1], 'view1 should show');
|
||||
assert.deepEqual(seq.elements, [view1]);
|
||||
testObject.setVisible('view1', true);
|
||||
assert.deepEqual(testObject.visibleViewDescriptors, [view1], 'view1 should show');
|
||||
assert.deepEqual(target.elements, [view1]);
|
||||
|
||||
model.setVisible('view3', true);
|
||||
assert.deepEqual(model.visibleViewDescriptors, [view1, view3], 'view3 should show');
|
||||
assert.deepEqual(seq.elements, [view1, view3]);
|
||||
testObject.setVisible('view3', true);
|
||||
assert.deepEqual(testObject.visibleViewDescriptors, [view1, view3], 'view3 should show');
|
||||
assert.deepEqual(target.elements, [view1, view3]);
|
||||
|
||||
model.setVisible('view2', true);
|
||||
assert.deepEqual(model.visibleViewDescriptors, [view1, view2, view3], 'view2 should show');
|
||||
assert.deepEqual(seq.elements, [view1, view2, view3]);
|
||||
testObject.setVisible('view2', true);
|
||||
assert.deepEqual(testObject.visibleViewDescriptors, [view1, view2, view3], 'view2 should show');
|
||||
assert.deepEqual(target.elements, [view1, view2, view3]);
|
||||
|
||||
viewsDescriptorsModel.removeViews([view1, view2, view3]);
|
||||
assert.deepEqual(model.visibleViewDescriptors, []);
|
||||
assert.deepEqual(seq.elements, []);
|
||||
ViewsRegistry.deregisterViews([view1, view2, view3], container);
|
||||
assert.deepEqual(testObject.visibleViewDescriptors, []);
|
||||
assert.deepEqual(target.elements, []);
|
||||
});
|
||||
|
||||
test('move', () => {
|
||||
const viewsDescriptorsModel = new ViewDescriptorsModel(contextKeyService);
|
||||
const model = new ViewsModel(viewsDescriptorsModel);
|
||||
const seq = new ViewDescriptorSequence(model);
|
||||
|
||||
container = ViewContainerRegistry.registerViewContainer({ id: 'test', name: 'test', ctorDescriptor: new SyncDescriptor(<any>{}) }, ViewContainerLocation.Sidebar);
|
||||
const testObject = viewDescriptorService.getViewContainerModel(container);
|
||||
const target = disposableStore.add(new ViewDescriptorSequence(testObject));
|
||||
const view1: IViewDescriptor = { id: 'view1', ctorDescriptor: null!, name: 'Test View 1' };
|
||||
const view2: IViewDescriptor = { id: 'view2', ctorDescriptor: null!, name: 'Test View 2' };
|
||||
const view3: IViewDescriptor = { id: 'view3', ctorDescriptor: null!, name: 'Test View 3' };
|
||||
|
||||
viewsDescriptorsModel.addViews([view1, view2, view3]);
|
||||
assert.deepEqual(model.visibleViewDescriptors, [view1, view2, view3], 'model views should be OK');
|
||||
assert.deepEqual(seq.elements, [view1, view2, view3], 'sql views should be OK');
|
||||
ViewsRegistry.registerViews([view1, view2, view3], container);
|
||||
assert.deepEqual(testObject.visibleViewDescriptors, [view1, view2, view3], 'model views should be OK');
|
||||
assert.deepEqual(target.elements, [view1, view2, view3], 'sql views should be OK');
|
||||
|
||||
model.move('view3', 'view1');
|
||||
assert.deepEqual(model.visibleViewDescriptors, [view3, view1, view2], 'view3 should go to the front');
|
||||
assert.deepEqual(seq.elements, [view3, view1, view2]);
|
||||
testObject.move('view3', 'view1');
|
||||
assert.deepEqual(testObject.visibleViewDescriptors, [view3, view1, view2], 'view3 should go to the front');
|
||||
assert.deepEqual(target.elements, [view3, view1, view2]);
|
||||
|
||||
model.move('view1', 'view2');
|
||||
assert.deepEqual(model.visibleViewDescriptors, [view3, view2, view1], 'view1 should go to the end');
|
||||
assert.deepEqual(seq.elements, [view3, view2, view1]);
|
||||
testObject.move('view1', 'view2');
|
||||
assert.deepEqual(testObject.visibleViewDescriptors, [view3, view2, view1], 'view1 should go to the end');
|
||||
assert.deepEqual(target.elements, [view3, view2, view1]);
|
||||
|
||||
model.move('view1', 'view3');
|
||||
assert.deepEqual(model.visibleViewDescriptors, [view1, view3, view2], 'view1 should go to the front');
|
||||
assert.deepEqual(seq.elements, [view1, view3, view2]);
|
||||
testObject.move('view1', 'view3');
|
||||
assert.deepEqual(testObject.visibleViewDescriptors, [view1, view3, view2], 'view1 should go to the front');
|
||||
assert.deepEqual(target.elements, [view1, view3, view2]);
|
||||
|
||||
model.move('view2', 'view3');
|
||||
assert.deepEqual(model.visibleViewDescriptors, [view1, view2, view3], 'view2 should go to the middle');
|
||||
assert.deepEqual(seq.elements, [view1, view2, view3]);
|
||||
testObject.move('view2', 'view3');
|
||||
assert.deepEqual(testObject.visibleViewDescriptors, [view1, view2, view3], 'view2 should go to the middle');
|
||||
assert.deepEqual(target.elements, [view1, view2, view3]);
|
||||
});
|
||||
|
||||
test('view states', async function () {
|
||||
const viewStates = new Map<string, IViewState>();
|
||||
viewStates.set('view1', { visibleGlobal: false, collapsed: false, visibleWorkspace: undefined });
|
||||
const viewsDescriptorsModel = new ViewDescriptorsModel(contextKeyService);
|
||||
const model = new ViewsModel(viewsDescriptorsModel, viewStates);
|
||||
const seq = new ViewDescriptorSequence(model);
|
||||
storageService.store(`${container.id}.state.hidden`, JSON.stringify([{ id: 'view1', isHidden: true }]), StorageScope.GLOBAL);
|
||||
container = ViewContainerRegistry.registerViewContainer({ id: 'test', name: 'test', ctorDescriptor: new SyncDescriptor(<any>{}) }, ViewContainerLocation.Sidebar);
|
||||
const testObject = viewDescriptorService.getViewContainerModel(container);
|
||||
const target = disposableStore.add(new ViewDescriptorSequence(testObject));
|
||||
|
||||
assert.equal(model.visibleViewDescriptors.length, 0);
|
||||
assert.equal(seq.elements.length, 0);
|
||||
assert.equal(testObject.visibleViewDescriptors.length, 0);
|
||||
assert.equal(target.elements.length, 0);
|
||||
|
||||
const viewDescriptor: IViewDescriptor = {
|
||||
id: 'view1',
|
||||
@@ -259,20 +272,19 @@ suite('ContributableViewsModel', () => {
|
||||
name: 'Test View 1'
|
||||
};
|
||||
|
||||
viewsDescriptorsModel.addViews([viewDescriptor]);
|
||||
assert.equal(model.visibleViewDescriptors.length, 0, 'view should not appear since it was set not visible in view state');
|
||||
assert.equal(seq.elements.length, 0);
|
||||
ViewsRegistry.registerViews([viewDescriptor], container);
|
||||
assert.equal(testObject.visibleViewDescriptors.length, 0, 'view should not appear since it was set not visible in view state');
|
||||
assert.equal(target.elements.length, 0);
|
||||
});
|
||||
|
||||
test('view states and when contexts', async function () {
|
||||
const viewStates = new Map<string, IViewState>();
|
||||
viewStates.set('view1', { visibleGlobal: false, collapsed: false, visibleWorkspace: undefined });
|
||||
const viewsDescriptorsModel = new ViewDescriptorsModel(contextKeyService);
|
||||
const model = new ViewsModel(viewsDescriptorsModel, viewStates);
|
||||
const seq = new ViewDescriptorSequence(model);
|
||||
storageService.store(`${container.id}.state.hidden`, JSON.stringify([{ id: 'view1', isHidden: true }]), StorageScope.GLOBAL);
|
||||
container = ViewContainerRegistry.registerViewContainer({ id: 'test', name: 'test', ctorDescriptor: new SyncDescriptor(<any>{}) }, ViewContainerLocation.Sidebar);
|
||||
const testObject = viewDescriptorService.getViewContainerModel(container);
|
||||
const target = disposableStore.add(new ViewDescriptorSequence(testObject));
|
||||
|
||||
assert.equal(model.visibleViewDescriptors.length, 0);
|
||||
assert.equal(seq.elements.length, 0);
|
||||
assert.equal(testObject.visibleViewDescriptors.length, 0);
|
||||
assert.equal(target.elements.length, 0);
|
||||
|
||||
const viewDescriptor: IViewDescriptor = {
|
||||
id: 'view1',
|
||||
@@ -281,29 +293,28 @@ suite('ContributableViewsModel', () => {
|
||||
when: ContextKeyExpr.equals('showview1', true)
|
||||
};
|
||||
|
||||
viewsDescriptorsModel.addViews([viewDescriptor]);
|
||||
assert.equal(model.visibleViewDescriptors.length, 0, 'view should not appear since context isnt in');
|
||||
assert.equal(seq.elements.length, 0);
|
||||
ViewsRegistry.registerViews([viewDescriptor], container);
|
||||
assert.equal(testObject.visibleViewDescriptors.length, 0, 'view should not appear since context isnt in');
|
||||
assert.equal(target.elements.length, 0);
|
||||
|
||||
const key = contextKeyService.createKey('showview1', false);
|
||||
assert.equal(model.visibleViewDescriptors.length, 0, 'view should still not appear since showview1 isnt true');
|
||||
assert.equal(seq.elements.length, 0);
|
||||
assert.equal(testObject.visibleViewDescriptors.length, 0, 'view should still not appear since showview1 isnt true');
|
||||
assert.equal(target.elements.length, 0);
|
||||
|
||||
key.set(true);
|
||||
await new Promise(c => setTimeout(c, 30));
|
||||
assert.equal(model.visibleViewDescriptors.length, 0, 'view should still not appear since it was set not visible in view state');
|
||||
assert.equal(seq.elements.length, 0);
|
||||
assert.equal(testObject.visibleViewDescriptors.length, 0, 'view should still not appear since it was set not visible in view state');
|
||||
assert.equal(target.elements.length, 0);
|
||||
});
|
||||
|
||||
test('view states and when contexts multiple views', async function () {
|
||||
const viewStates = new Map<string, IViewState>();
|
||||
viewStates.set('view1', { visibleGlobal: false, collapsed: false, visibleWorkspace: undefined });
|
||||
const viewsDescriptorsModel = new ViewDescriptorsModel(contextKeyService);
|
||||
const model = new ViewsModel(viewsDescriptorsModel, viewStates);
|
||||
const seq = new ViewDescriptorSequence(model);
|
||||
storageService.store(`${container.id}.state.hidden`, JSON.stringify([{ id: 'view1', isHidden: true }]), StorageScope.GLOBAL);
|
||||
container = ViewContainerRegistry.registerViewContainer({ id: 'test', name: 'test', ctorDescriptor: new SyncDescriptor(<any>{}) }, ViewContainerLocation.Sidebar);
|
||||
const testObject = viewDescriptorService.getViewContainerModel(container);
|
||||
const target = disposableStore.add(new ViewDescriptorSequence(testObject));
|
||||
|
||||
assert.equal(model.visibleViewDescriptors.length, 0);
|
||||
assert.equal(seq.elements.length, 0);
|
||||
assert.equal(testObject.visibleViewDescriptors.length, 0);
|
||||
assert.equal(target.elements.length, 0);
|
||||
|
||||
const view1: IViewDescriptor = {
|
||||
id: 'view1',
|
||||
@@ -323,30 +334,29 @@ suite('ContributableViewsModel', () => {
|
||||
when: ContextKeyExpr.equals('showview', true)
|
||||
};
|
||||
|
||||
viewsDescriptorsModel.addViews([view1, view2, view3]);
|
||||
assert.deepEqual(model.visibleViewDescriptors, [view2], 'Only view2 should be visible');
|
||||
assert.deepEqual(seq.elements, [view2]);
|
||||
ViewsRegistry.registerViews([view1, view2, view3], container);
|
||||
assert.deepEqual(testObject.visibleViewDescriptors, [view2], 'Only view2 should be visible');
|
||||
assert.deepEqual(target.elements, [view2]);
|
||||
|
||||
const key = contextKeyService.createKey('showview', false);
|
||||
assert.deepEqual(model.visibleViewDescriptors, [view2], 'Only view2 should be visible');
|
||||
assert.deepEqual(seq.elements, [view2]);
|
||||
assert.deepEqual(testObject.visibleViewDescriptors, [view2], 'Only view2 should be visible');
|
||||
assert.deepEqual(target.elements, [view2]);
|
||||
|
||||
key.set(true);
|
||||
await new Promise(c => setTimeout(c, 30));
|
||||
assert.deepEqual(model.visibleViewDescriptors, [view2, view3], 'view3 should be visible');
|
||||
assert.deepEqual(seq.elements, [view2, view3]);
|
||||
assert.deepEqual(testObject.visibleViewDescriptors, [view2, view3], 'view3 should be visible');
|
||||
assert.deepEqual(target.elements, [view2, view3]);
|
||||
|
||||
key.set(false);
|
||||
await new Promise(c => setTimeout(c, 30));
|
||||
assert.deepEqual(model.visibleViewDescriptors, [view2], 'Only view2 should be visible');
|
||||
assert.deepEqual(seq.elements, [view2]);
|
||||
assert.deepEqual(testObject.visibleViewDescriptors, [view2], 'Only view2 should be visible');
|
||||
assert.deepEqual(target.elements, [view2]);
|
||||
});
|
||||
|
||||
test('remove event is not triggered if view was hidden and removed', async function () {
|
||||
const viewsDescriptorsModel = new ViewDescriptorsModel(contextKeyService);
|
||||
const model = new ViewsModel(viewsDescriptorsModel);
|
||||
const seq = new ViewDescriptorSequence(model);
|
||||
|
||||
container = ViewContainerRegistry.registerViewContainer({ id: 'test', name: 'test', ctorDescriptor: new SyncDescriptor(<any>{}) }, ViewContainerLocation.Sidebar);
|
||||
const testObject = viewDescriptorService.getViewContainerModel(container);
|
||||
const target = disposableStore.add(new ViewDescriptorSequence(testObject));
|
||||
const viewDescriptor: IViewDescriptor = {
|
||||
id: 'view1',
|
||||
ctorDescriptor: null!,
|
||||
@@ -355,21 +365,21 @@ suite('ContributableViewsModel', () => {
|
||||
canToggleVisibility: true
|
||||
};
|
||||
|
||||
viewsDescriptorsModel.addViews([viewDescriptor]);
|
||||
ViewsRegistry.registerViews([viewDescriptor], container);
|
||||
|
||||
const key = contextKeyService.createKey('showview1', true);
|
||||
await new Promise(c => setTimeout(c, 30));
|
||||
assert.equal(model.visibleViewDescriptors.length, 1, 'view should appear after context is set');
|
||||
assert.equal(seq.elements.length, 1);
|
||||
assert.equal(testObject.visibleViewDescriptors.length, 1, 'view should appear after context is set');
|
||||
assert.equal(target.elements.length, 1);
|
||||
|
||||
model.setVisible('view1', false);
|
||||
assert.equal(model.visibleViewDescriptors.length, 0, 'view should disappear after setting visibility to false');
|
||||
assert.equal(seq.elements.length, 0);
|
||||
testObject.setVisible('view1', false);
|
||||
assert.equal(testObject.visibleViewDescriptors.length, 0, 'view should disappear after setting visibility to false');
|
||||
assert.equal(target.elements.length, 0);
|
||||
|
||||
const target = sinon.spy(model.onDidRemove);
|
||||
const targetEvent = sinon.spy(testObject.onDidRemoveVisibleViewDescriptors);
|
||||
key.set(false);
|
||||
await new Promise(c => setTimeout(c, 30));
|
||||
assert.ok(!target.called, 'remove event should not be called since it is already hidden');
|
||||
assert.ok(!targetEvent.called, 'remove event should not be called since it is already hidden');
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user