Skip to content

Commit f60d780

Browse files
committed
- Enable/Disable viewlets by views when context - Move viewlet enablement/disablement to views service - Fix - adopt if a viewlet extension is disabled/removed
1 parent 7eff96c commit f60d780

10 files changed

Lines changed: 93 additions & 66 deletions

File tree

src/vs/workbench/api/browser/viewsContainersExtensionPoint.ts

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -80,12 +80,11 @@ class ViewsContainersExtensionHandler implements IWorkbenchContribution {
8080
}
8181

8282
private registerTestViewContainer(): void {
83-
const id = 'test';
8483
const title = localize('test', "Test");
85-
const cssClass = `extensionViewlet-${id}`;
84+
const cssClass = `extensionViewlet-test`;
8685
const icon = require.toUrl('./media/test.svg');
8786

88-
this.registerCustomViewlet({ id, title, icon }, TEST_VIEW_CONTAINER_ORDER, cssClass);
87+
this.registerCustomViewlet({ id: ViewLocation.TEST.id, title, icon }, TEST_VIEW_CONTAINER_ORDER, cssClass);
8988
}
9089

9190
private handleAndRegisterCustomViewContainers() {
@@ -139,13 +138,13 @@ class ViewsContainersExtensionHandler implements IWorkbenchContribution {
139138
const cssClass = `extensionViewlet-${descriptor.id}`;
140139
// TODO@extensionLocation
141140
const icon = join(extension.extensionLocation.fsPath, descriptor.icon);
142-
this.registerCustomViewlet({ id: descriptor.id, title: descriptor.title, icon }, TEST_VIEW_CONTAINER_ORDER + index + 1, cssClass);
141+
this.registerCustomViewlet({ id: `workbench.view.extension.${descriptor.id}`, title: descriptor.title, icon }, TEST_VIEW_CONTAINER_ORDER + index + 1, cssClass);
143142
});
144143
}
145144

146145
private registerCustomViewlet(descriptor: IUserFriendlyViewsContainerDescriptor, order: number, cssClass: string): void {
147146
const viewletRegistry = Registry.as<ViewletRegistry>(ViewletExtensions.Viewlets);
148-
const id = `workbench.view.extension.${descriptor.id}`;
147+
const id = descriptor.id;
149148

150149
if (!viewletRegistry.getViewlet(id)) {
151150

src/vs/workbench/browser/parts/activitybar/activitybarPart.ts

Lines changed: 15 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ import { ACTIVITY_BAR_BACKGROUND, ACTIVITY_BAR_BORDER, ACTIVITY_BAR_FOREGROUND,
2525
import { contrastBorder } from 'vs/platform/theme/common/colorRegistry';
2626
import { CompositeBar } from 'vs/workbench/browser/parts/compositebar/compositeBar';
2727
import { ToggleCompositePinnedAction, ICompositeBar } from 'vs/workbench/browser/parts/compositebar/compositeBarActions';
28-
import { ViewLocation, ViewsRegistry } from 'vs/workbench/common/views';
2928
import { ViewletDescriptor } from 'vs/workbench/browser/viewlet';
3029
import { Dimension, createCSSRule } from 'vs/base/browser/dom';
3130
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
@@ -57,7 +56,6 @@ export class ActivitybarPart extends Part {
5756
private globalActivityIdToActions: { [globalActivityId: string]: GlobalActivityAction; };
5857

5958
private placeholderComposites: IPlaceholderComposite[] = [];
60-
private extensionsRegistrationCompleted: boolean = false;
6159
private compositeBar: CompositeBar;
6260
private compositeActions: { [compositeId: string]: { activityAction: ViewletActivityAction, pinnedAction: ToggleCompositePinnedAction } };
6361

@@ -101,16 +99,13 @@ export class ActivitybarPart extends Part {
10199
}
102100

103101
private onDidRegisterExtensions(): void {
104-
this.extensionsRegistrationCompleted = true;
105102
this.removeNotExistingPlaceholderComposites();
106103
this.updateCompositebar();
107104
}
108105

109106
private registerListeners(): void {
110107

111108
this.toUnbind.push(this.viewletService.onDidViewletRegister(() => this.updateCompositebar()));
112-
this.toUnbind.push(ViewsRegistry.onViewsRegistered(() => this.updateCompositebar()));
113-
this.toUnbind.push(ViewsRegistry.onViewsDeregistered(() => this.updateCompositebar()));
114109

115110
// Activate viewlet action on opening of a viewlet
116111
this.toUnbind.push(this.viewletService.onDidViewletOpen(viewlet => this.compositeBar.activateComposite(viewlet.getId())));
@@ -119,7 +114,7 @@ export class ActivitybarPart extends Part {
119114
this.toUnbind.push(this.viewletService.onDidViewletClose(viewlet => this.compositeBar.deactivateComposite(viewlet.getId())));
120115
this.toUnbind.push(this.viewletService.onDidViewletEnablementChange(({ id, enabled }) => {
121116
if (enabled) {
122-
this.compositeBar.addComposite(this.viewletService.getViewlet(id), true);
117+
this.compositeBar.addComposite(this.viewletService.getViewlet(id));
123118
} else {
124119
this.removeComposite(id);
125120
}
@@ -226,26 +221,18 @@ export class ActivitybarPart extends Part {
226221
private updateCompositebar(): void {
227222
const viewlets = this.viewletService.getViewlets();
228223
for (const viewlet of viewlets) {
229-
const hasPlaceholder = this.placeholderComposites.some(c => c.id === viewlet.id);
230-
231-
// Add the composite if it has views registered or
232-
// If it was existing before and the extensions registration is not yet completed.
233-
if (this.hasRegisteredViews(viewlet)
234-
|| (hasPlaceholder && !this.extensionsRegistrationCompleted)
235-
) {
236-
this.compositeBar.addComposite(viewlet, false);
237-
// Pin it by default if it is new => it does not has a placeholder
238-
if (!hasPlaceholder) {
239-
this.compositeBar.pin(viewlet.id);
240-
}
241-
this.enableCompositeActions(viewlet);
242-
const activeViewlet = this.viewletService.getActiveViewlet();
243-
if (activeViewlet && activeViewlet.getId() === viewlet.id) {
244-
this.compositeBar.pin(viewlet.id);
245-
this.compositeBar.activateComposite(viewlet.id);
246-
}
247-
} else {
248-
this.removeComposite(viewlet.id);
224+
this.compositeBar.addComposite(viewlet);
225+
226+
// Pin it by default if it is new => it does not has a placeholder
227+
if (this.placeholderComposites.every(c => c.id !== viewlet.id)) {
228+
this.compositeBar.pin(viewlet.id);
229+
}
230+
231+
this.enableCompositeActions(viewlet);
232+
const activeViewlet = this.viewletService.getActiveViewlet();
233+
if (activeViewlet && activeViewlet.getId() === viewlet.id) {
234+
this.compositeBar.pin(viewlet.id);
235+
this.compositeBar.activateComposite(viewlet.id);
249236
}
250237
}
251238
}
@@ -254,7 +241,7 @@ export class ActivitybarPart extends Part {
254241
const viewlets = this.viewletService.getViewlets();
255242
for (const { id } of this.placeholderComposites) {
256243
if (viewlets.every(viewlet => viewlet.id !== id)) {
257-
this.compositeBar.addComposite({ id, name: id, order: void 0 }, false);
244+
this.compositeBar.addComposite({ id, name: id, order: void 0 });
258245
}
259246
}
260247
}
@@ -288,14 +275,6 @@ export class ActivitybarPart extends Part {
288275
}
289276
}
290277

291-
private hasRegisteredViews(viewlet: ViewletDescriptor): boolean {
292-
const viewLocation = ViewLocation.get(viewlet.id);
293-
if (viewLocation) {
294-
return ViewsRegistry.getViews(viewLocation).length > 0;
295-
}
296-
return true;
297-
}
298-
299278
public getPinned(): string[] {
300279
return this.viewletService.getViewlets().map(v => v.id).filter(id => this.compositeBar.isPinned(id));
301280
}
@@ -324,7 +303,7 @@ export class ActivitybarPart extends Part {
324303
}
325304

326305
public shutdown(): void {
327-
const state = this.viewletService.getViewlets().filter(viewlet => this.hasRegisteredViews(viewlet)).map(viewlet => ({ id: viewlet.id, iconUrl: viewlet.iconUrl }));
306+
const state = this.viewletService.getViewlets().filter(viewlet => this.compositeBar.isPinned(viewlet.id)).map(viewlet => ({ id: viewlet.id, iconUrl: viewlet.iconUrl }));
328307
this.storageService.store(ActivitybarPart.PLACEHOLDER_VIEWLETS, JSON.stringify(state), StorageScope.GLOBAL);
329308
super.shutdown();
330309
}

src/vs/workbench/browser/parts/compositebar/compositeBar.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ export class CompositeBar extends Widget implements ICompositeBar {
118118
this.updateCompositeSwitcher();
119119
}
120120

121-
public addComposite({ id, name, order }: { id: string; name: string, order: number }, open: boolean): void {
121+
public addComposite({ id, name, order }: { id: string; name: string, order: number }): void {
122122
const state = this.storedState.filter(s => s.id === id)[0];
123123
const pinned = state ? state.pinned : true;
124124
let index = order >= 0 ? order : this.model.items.length;
@@ -139,8 +139,8 @@ export class CompositeBar extends Widget implements ICompositeBar {
139139
// Add to the model
140140
if (this.model.add(id, name, order, index)) {
141141
this.computeSizes([this.model.findItem(id)]);
142-
if (pinned || open) {
143-
this.pin(id, open);
142+
if (pinned) {
143+
this.pin(id);
144144
} else {
145145
this.updateCompositeSwitcher();
146146
}

src/vs/workbench/browser/parts/panel/panelPart.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ export class PanelPart extends CompositePart<Panel> implements IPanelService {
105105
});
106106
this.toUnbind.push(this.compositeBar);
107107
for (const panel of this.getPanels()) {
108-
this.compositeBar.addComposite(panel, false);
108+
this.compositeBar.addComposite(panel);
109109
}
110110
this.activePanelContextKey = ActivePanelContext.bindTo(contextKeyService);
111111
this.onDidPanelOpen(this._onDidPanelOpen, this, this.disposables);
@@ -116,7 +116,7 @@ export class PanelPart extends CompositePart<Panel> implements IPanelService {
116116

117117
private registerListeners(): void {
118118

119-
this.toUnbind.push(this.registry.onDidRegister(panelDescriptor => this.compositeBar.addComposite(panelDescriptor, false)));
119+
this.toUnbind.push(this.registry.onDidRegister(panelDescriptor => this.compositeBar.addComposite(panelDescriptor)));
120120

121121
// Activate panel action on opening of a panel
122122
this.toUnbind.push(this.onDidPanelOpen(panel => {
@@ -198,7 +198,7 @@ export class PanelPart extends CompositePart<Panel> implements IPanelService {
198198
if (descriptor && descriptor.enabled !== enabled) {
199199
descriptor.enabled = enabled;
200200
if (enabled) {
201-
this.compositeBar.addComposite(descriptor, true);
201+
this.compositeBar.addComposite(descriptor);
202202
} else {
203203
this.removeComposite(id);
204204
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ export interface IViewItem {
5555
active: boolean;
5656
}
5757

58-
class ViewDescriptorCollection {
58+
export class ViewDescriptorCollection {
5959

6060
private contextKeys = new CounterSet<string>();
6161
private items: IViewItem[] = [];

src/vs/workbench/browser/parts/views/customView.ts renamed to src/vs/workbench/browser/parts/views/views.ts

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,18 +33,30 @@ import { FileIconThemableWorkbenchTree } from 'vs/workbench/browser/parts/views/
3333
import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet';
3434
import { isUndefinedOrNull } from 'vs/base/common/types';
3535
import { Emitter, Event } from 'vs/base/common/event';
36+
import { ViewDescriptorCollection } from './contributableViews';
37+
import { Registry } from 'vs/platform/registry/common/platform';
38+
import { ViewletRegistry, Extensions as ViewletExtensions } from 'vs/workbench/browser/viewlet';
39+
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
40+
import { ILifecycleService, LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle';
3641

37-
export class CustomViewsService extends Disposable implements IViewsService {
42+
export class ViewsService extends Disposable implements IViewsService {
3843

3944
_serviceBrand: any;
4045

4146
private viewers: Map<string, CustomTreeViewer> = new Map<string, CustomTreeViewer>();
4247

4348
constructor(
4449
@IInstantiationService private instantiationService: IInstantiationService,
45-
@IViewletService private viewletService: IViewletService
50+
@ILifecycleService private lifecycleService: ILifecycleService,
51+
@IViewletService private viewletService: IViewletService,
52+
@IStorageService private storageService: IStorageService
4653
) {
4754
super();
55+
56+
ViewLocation.all.forEach(viewLocation => this.onDidRegisterViewLocation(viewLocation));
57+
this._register(ViewLocation.onDidRegister(viewLocation => this.onDidRegisterViewLocation(viewLocation)));
58+
this._register(Registry.as<ViewletRegistry>(ViewletExtensions.Viewlets).onDidRegister(viewlet => this.viewletService.setViewletEnablement(viewlet.id, this.storageService.getBoolean(`viewservice.${viewlet.id}.enablement`, StorageScope.GLOBAL, viewlet.id !== ViewLocation.TEST.id))));
59+
4860
this.createViewers(ViewsRegistry.getAllViews());
4961
this._register(ViewsRegistry.onViewsRegistered(viewDescriptors => this.createViewers(viewDescriptors)));
5062
this._register(ViewsRegistry.onViewsDeregistered(viewDescriptors => this.removeViewers(viewDescriptors)));
@@ -72,6 +84,18 @@ export class CustomViewsService extends Disposable implements IViewsService {
7284
return TPromise.as(null);
7385
}
7486

87+
private onDidRegisterViewLocation(viewLocation: ViewLocation): void {
88+
const viewDescriptorCollection = this._register(this.instantiationService.createInstance(ViewDescriptorCollection, viewLocation));
89+
this._register(viewDescriptorCollection.onDidChange(() => this.updateViewletEnablement(viewLocation, viewDescriptorCollection)));
90+
this.lifecycleService.when(LifecyclePhase.Eventually).then(() => this.updateViewletEnablement(viewLocation, viewDescriptorCollection));
91+
}
92+
93+
private updateViewletEnablement(viewLocation: ViewLocation, viewDescriptorCollection: ViewDescriptorCollection): void {
94+
const enabled = viewDescriptorCollection.viewDescriptors.length > 0;
95+
this.viewletService.setViewletEnablement(viewLocation.id, enabled);
96+
this.storageService.store(`viewservice.${viewLocation.id}.enablement`, enabled, StorageScope.GLOBAL);
97+
}
98+
7599
private createViewers(viewDescriptors: IViewDescriptor[]): void {
76100
for (const viewDescriptor of viewDescriptors) {
77101
if ((<ICustomViewDescriptor>viewDescriptor).treeView) {

src/vs/workbench/common/views.ts

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,23 +14,34 @@ import { IViewlet } from 'vs/workbench/common/viewlet';
1414
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
1515
import { IDisposable } from 'vs/base/common/lifecycle';
1616
import { ThemeIcon } from 'vs/platform/theme/common/themeService';
17+
import { values } from 'vs/base/common/map';
1718

1819
export class ViewLocation {
1920

21+
private static readonly _onDidRegister: Emitter<ViewLocation> = new Emitter<ViewLocation>();
22+
static readonly onDidRegister: Event<ViewLocation> = ViewLocation._onDidRegister.event;
23+
2024
private static locations: Map<string, ViewLocation> = new Map<string, ViewLocation>();
2125
static register(id: string): ViewLocation {
22-
const viewLocation = new ViewLocation(id);
23-
ViewLocation.locations.set(id, viewLocation);
24-
return viewLocation;
26+
if (!ViewLocation.locations.has(id)) {
27+
const viewLocation = new ViewLocation(id);
28+
ViewLocation.locations.set(id, viewLocation);
29+
ViewLocation._onDidRegister.fire(viewLocation);
30+
}
31+
return ViewLocation.get(id);
2532
}
2633
static get(value: string): ViewLocation {
2734
return ViewLocation.locations.get(value);
2835
}
36+
static get all(): ViewLocation[] {
37+
return values(ViewLocation.locations);
38+
}
2939

3040
static readonly Explorer: ViewLocation = ViewLocation.register('workbench.view.explorer');
3141
static readonly Debug: ViewLocation = ViewLocation.register('workbench.view.debug');
3242
static readonly Extensions: ViewLocation = ViewLocation.register('workbench.view.extensions');
3343
static readonly SCM: ViewLocation = ViewLocation.register('workbench.view.scm.views.contributed');
44+
static readonly TEST: ViewLocation = ViewLocation.register('workbench.view.extension.test');
3445

3546
private constructor(private _id: string) { }
3647
get id(): string { return this._id; }

src/vs/workbench/electron-browser/workbench.ts

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ import { IListService, ListService } from 'vs/platform/list/browser/listService'
9898
import { domEvent } from 'vs/base/browser/event';
9999
import { InputFocusedContext } from 'vs/platform/workbench/common/contextkeys';
100100
import { IViewsService } from 'vs/workbench/common/views';
101-
import { CustomViewsService } from 'vs/workbench/browser/parts/views/customView';
101+
import { ViewsService } from 'vs/workbench/browser/parts/views/views';
102102
import { INotificationService } from 'vs/platform/notification/common/notification';
103103
import { NotificationService } from 'vs/workbench/services/notification/common/notificationService';
104104
import { NotificationsCenter } from 'vs/workbench/browser/parts/notifications/notificationsCenter';
@@ -387,9 +387,11 @@ export class Workbench implements IPartService {
387387
}
388388

389389
perf.mark('willRestoreViewlet');
390-
restorePromises.push(this.viewletService.openViewlet(viewletIdToRestore).then(() => {
391-
perf.mark('didRestoreViewlet');
392-
}));
390+
restorePromises.push(this.viewletService.openViewlet(viewletIdToRestore)
391+
.then(viewlet => viewlet || this.viewletService.openViewlet(this.viewletService.getDefaultViewletId()))
392+
.then(() => {
393+
perf.mark('didRestoreViewlet');
394+
}));
393395
}
394396

395397
// Restore Panel
@@ -575,7 +577,7 @@ export class Workbench implements IPartService {
575577
serviceCollection.set(IPanelService, this.panelPart);
576578

577579
// Custom views service
578-
const customViewsService = this.instantiationService.createInstance(CustomViewsService);
580+
const customViewsService = this.instantiationService.createInstance(ViewsService);
579581
serviceCollection.set(IViewsService, customViewsService);
580582

581583
// Activity service (activitybar part)
@@ -872,7 +874,8 @@ export class Workbench implements IPartService {
872874
else if (!hidden && !this.sidebarPart.getActiveViewlet()) {
873875
const viewletToOpen = this.sidebarPart.getLastActiveViewletId();
874876
if (viewletToOpen) {
875-
promise = this.sidebarPart.openViewlet(viewletToOpen, true);
877+
promise = this.viewletService.openViewlet(viewletToOpen, true)
878+
.then(viewlet => viewlet || this.viewletService.openViewlet(this.viewletService.getDefaultViewletId(), true));
876879
}
877880
}
878881

src/vs/workbench/parts/search/browser/searchViewLocationUpdater.ts

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,23 +16,29 @@ export class SearchViewLocationUpdater implements IWorkbenchContribution {
1616
@IPanelService panelService: IPanelService,
1717
@IConfigurationService configurationService: IConfigurationService
1818
) {
19-
const updateSearchViewLocation = () => {
19+
const updateSearchViewLocation = (open: boolean) => {
2020
const config = configurationService.getValue<ISearchConfiguration>();
2121
if (config.search.location === 'panel') {
2222
viewletService.setViewletEnablement(VIEW_ID, false);
2323
panelService.setPanelEnablement(VIEW_ID, true);
24+
if (open) {
25+
panelService.openPanel(VIEW_ID);
26+
}
2427
} else {
2528
panelService.setPanelEnablement(VIEW_ID, false);
2629
viewletService.setViewletEnablement(VIEW_ID, true);
30+
if (open) {
31+
viewletService.openViewlet(VIEW_ID);
32+
}
2733
}
2834
};
2935

3036
configurationService.onDidChangeConfiguration(e => {
3137
if (e.affectsConfiguration('search.location')) {
32-
updateSearchViewLocation();
38+
updateSearchViewLocation(true);
3339
}
3440
});
3541

36-
updateSearchViewLocation();
42+
updateSearchViewLocation(false);
3743
}
3844
}

0 commit comments

Comments
 (0)