提交 3a88dae3 编写于 作者: S Sandeep Somavarapu

Debt: Merge pinned viewlets and cached viewlets into one key

上级 f041bc0c
......@@ -20,22 +20,26 @@ import { ToggleActivityBarVisibilityAction } from 'vs/workbench/browser/actions/
import { IThemeService, ITheme } from 'vs/platform/theme/common/themeService';
import { ACTIVITY_BAR_BACKGROUND, ACTIVITY_BAR_BORDER, ACTIVITY_BAR_FOREGROUND, ACTIVITY_BAR_BADGE_BACKGROUND, ACTIVITY_BAR_BADGE_FOREGROUND, ACTIVITY_BAR_DRAG_AND_DROP_BACKGROUND, ACTIVITY_BAR_INACTIVE_FOREGROUND } from 'vs/workbench/common/theme';
import { contrastBorder } from 'vs/platform/theme/common/colorRegistry';
import { CompositeBar } from 'vs/workbench/browser/parts/compositeBar';
import { CompositeBar, ICompositeBarItem } from 'vs/workbench/browser/parts/compositeBar';
import { Dimension, addClass } from 'vs/base/browser/dom';
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
import { URI } from 'vs/base/common/uri';
import { URI, UriComponents } from 'vs/base/common/uri';
import { ToggleCompositePinnedAction, ICompositeBarColors } from 'vs/workbench/browser/parts/compositeBarActions';
import { ViewletDescriptor } from 'vs/workbench/browser/viewlet';
import { IViewsService, IViewContainersRegistry, Extensions as ViewContainerExtensions, ViewContainer, TEST_VIEW_CONTAINER_ID, IViewDescriptorCollection } from 'vs/workbench/common/views';
import { IContextKeyService, ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
import { IViewlet } from 'vs/workbench/common/viewlet';
import { isUndefinedOrNull } from 'vs/base/common/types';
const SCM_VIEWLET_ID = 'workbench.view.scm';
interface ICachedViewlet {
id: string;
iconUrl: URI;
iconUrl: UriComponents;
pinned: boolean;
order: number;
visible: boolean;
views?: { when: string }[];
}
......@@ -43,7 +47,6 @@ export class ActivitybarPart extends Part {
private static readonly ACTION_HEIGHT = 50;
private static readonly PINNED_VIEWLETS = 'workbench.activity.pinnedViewlets';
private static readonly CACHED_VIEWLETS = 'workbench.activity.placeholderViewlets';
private dimension: Dimension;
......@@ -67,9 +70,15 @@ export class ActivitybarPart extends Part {
) {
super(id, { hasTitle: false }, themeService, storageService);
this.compositeBar = this._register(this.instantiationService.createInstance(CompositeBar, {
this.cachedViewlets = this.loadCachedViewlets();
for (const cachedViewlet of this.cachedViewlets) {
if (this.shouldBeHidden(cachedViewlet.id, cachedViewlet)) {
cachedViewlet.visible = false;
}
}
this.compositeBar = this._register(this.instantiationService.createInstance(CompositeBar, this.cachedViewlets.map(v => (<ICompositeBarItem>{ id: v.id, name: void 0, visible: v.visible, order: v.order, pinned: v.pinned })), {
icon: true,
storageId: ActivitybarPart.PINNED_VIEWLETS,
orientation: ActionsOrientation.VERTICAL,
openComposite: (compositeId: string) => this.viewletService.openViewlet(compositeId, true),
getActivityAction: (compositeId: string) => this.getCompositeActions(compositeId).activityAction,
......@@ -83,19 +92,12 @@ export class ActivitybarPart extends Part {
overflowActionSize: ActivitybarPart.ACTION_HEIGHT
}));
const previousState = this.storageService.get(ActivitybarPart.CACHED_VIEWLETS, StorageScope.GLOBAL, '[]');
this.cachedViewlets = (<ICachedViewlet[]>JSON.parse(previousState)).map(({ id, iconUrl, views }) => ({ id, views, iconUrl: typeof iconUrl === 'object' ? URI.revive(iconUrl) : void 0 }));
for (const cachedViewlet of this.cachedViewlets) {
if (this.shouldBeHidden(cachedViewlet.id, cachedViewlet)) {
this.compositeBar.hideComposite(cachedViewlet.id);
}
}
this.registerListeners();
this.onDidRegisterViewlets(viewletService.getAllViewlets());
}
private registerListeners(): void {
this._register(this.compositeBar.onDidChange(() => this.saveCachedViewlets()));
this._register(this.viewletService.onDidViewletRegister(viewlet => this.onDidRegisterViewlets([viewlet])));
// Activate viewlet action on opening of a viewlet
......@@ -250,7 +252,7 @@ export class ActivitybarPart extends Part {
} else {
const cachedComposite = this.cachedViewlets.filter(c => c.id === compositeId)[0];
compositeActions = {
activityAction: this.instantiationService.createInstance(PlaceHolderViewletActivityAction, compositeId, cachedComposite && cachedComposite.iconUrl),
activityAction: this.instantiationService.createInstance(PlaceHolderViewletActivityAction, compositeId, cachedComposite ? URI.revive(cachedComposite.iconUrl) : void 0),
pinnedAction: new PlaceHolderToggleCompositePinnedAction(compositeId, this.compositeBar)
};
}
......@@ -290,7 +292,7 @@ export class ActivitybarPart extends Part {
private removeNotExistingComposites(): void {
const viewlets = this.viewletService.getAllViewlets();
for (const { id } of this.compositeBar.getComposites()) {
for (const { id } of this.cachedViewlets) {
if (viewlets.every(viewlet => viewlet.id !== id)) {
this.removeComposite(id, false);
}
......@@ -350,20 +352,52 @@ export class ActivitybarPart extends Part {
}
protected saveState(): void {
this.saveCachedViewlets();
super.saveState();
}
private saveCachedViewlets(): void {
const state: ICachedViewlet[] = [];
for (const { id, iconUrl } of this.viewletService.getAllViewlets()) {
const viewContainer = this.getViewContainer(id);
const views: { when: string }[] = [];
if (viewContainer) {
for (const { when } of this.viewsService.getViewDescriptors(viewContainer).allViewDescriptors) {
views.push({ when: when ? when.serialize() : void 0 });
const compositeItems = this.compositeBar.getComposites();
const allViewlets = this.viewletService.getAllViewlets();
for (const compositeItem of compositeItems) {
const viewContainer = this.getViewContainer(compositeItem.id);
const viewlet = allViewlets.filter(({ id }) => id === compositeItem.id)[0];
if (viewlet) {
const views: { when: string }[] = [];
if (viewContainer) {
for (const { when } of this.viewsService.getViewDescriptors(viewContainer).allViewDescriptors) {
views.push({ when: when ? when.serialize() : void 0 });
}
}
state.push({ id: compositeItem.id, iconUrl: viewlet.iconUrl, views, pinned: compositeItem && compositeItem.pinned, order: compositeItem ? compositeItem.order : void 0, visible: compositeItem && compositeItem.visible });
}
state.push({ id, iconUrl, views });
}
this.storageService.store(ActivitybarPart.CACHED_VIEWLETS, JSON.stringify(state), StorageScope.GLOBAL);
this.storageService.store(ActivitybarPart.PINNED_VIEWLETS, JSON.stringify(state), StorageScope.GLOBAL);
}
super.saveState();
private loadCachedViewlets(): ICachedViewlet[] {
const storedStates = <Array<string | ICachedViewlet>>JSON.parse(this.storageService.get(ActivitybarPart.PINNED_VIEWLETS, StorageScope.GLOBAL, '[]'));
const cachedViewlets = <ICachedViewlet[]>storedStates.map(c => {
const serialized: ICachedViewlet = typeof c === 'string' /* migration from pinned states to composites states */ ? <ICachedViewlet>{ id: c, pinned: true, order: void 0, visible: true, iconUrl: void 0, views: void 0 } : c;
serialized.visible = isUndefinedOrNull(serialized.visible) ? true : serialized.visible;
return serialized;
});
for (const old of this.loadOldCachedViewlets()) {
const cachedViewlet = cachedViewlets.filter(cached => cached.id === old.id)[0];
if (cachedViewlet) {
cachedViewlet.iconUrl = old.iconUrl;
cachedViewlet.views = old.views;
}
}
return cachedViewlets;
}
private loadOldCachedViewlets(): ICachedViewlet[] {
const previousState = this.storageService.get('workbench.activity.placeholderViewlets', StorageScope.GLOBAL, '[]');
const result = (<ICachedViewlet[]>JSON.parse(previousState));
this.storageService.remove('workbench.activity.placeholderViewlets', StorageScope.GLOBAL);
return result;
}
private getViewContainer(viewletId: string): ViewContainer | undefined {
......
......@@ -9,7 +9,6 @@ import { illegalArgument } from 'vs/base/common/errors';
import * as arrays from 'vs/base/common/arrays';
import { IDisposable, toDisposable } from 'vs/base/common/lifecycle';
import { IBadge } from 'vs/workbench/services/activity/common/activity';
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { ActionBar, ActionsOrientation, Separator } from 'vs/base/browser/ui/actionbar/actionbar';
import { CompositeActionItem, CompositeOverflowActivityAction, ICompositeActivity, CompositeOverflowActivityActionItem, ActivityAction, ICompositeBar, ICompositeBarColors, DraggedCompositeIdentifier } from 'vs/workbench/browser/parts/compositeBarActions';
......@@ -20,10 +19,18 @@ import { Widget } from 'vs/base/browser/ui/widget';
import { isUndefinedOrNull } from 'vs/base/common/types';
import { LocalSelectionTransfer } from 'vs/workbench/browser/dnd';
import { ITheme } from 'vs/platform/theme/common/themeService';
import { Emitter, Event } from 'vs/base/common/event';
export interface ICompositeBarItem {
id: string;
name: string;
pinned: boolean;
order: number;
visible: boolean;
}
export interface ICompositeBarOptions {
icon: boolean;
storageId: string;
orientation: ActionsOrientation;
colors: (theme: ITheme) => ICompositeBarColors;
compositeSize: number;
......@@ -51,25 +58,28 @@ export class CompositeBar extends Widget implements ICompositeBar {
private compositeTransfer: LocalSelectionTransfer<DraggedCompositeIdentifier>;
private readonly _onDidChange: Emitter<void> = this._register(new Emitter<void>());
readonly onDidChange: Event<void> = this._onDidChange.event;
constructor(
items: ICompositeBarModelItem[],
private options: ICompositeBarOptions,
@IInstantiationService private instantiationService: IInstantiationService,
@IStorageService storageService: IStorageService,
@IContextMenuService private contextMenuService: IContextMenuService
) {
super();
this.model = new CompositeBarModel(options, storageService);
this.model = new CompositeBarModel(items, options);
this.visibleComposites = [];
this.compositeSizeInBar = new Map<string, number>();
this.compositeTransfer = LocalSelectionTransfer.getInstance<DraggedCompositeIdentifier>();
}
getComposites(): ICompositeBarItem[] {
getComposites(): ICompositeBarModelItem[] {
return [...this.model.items];
}
getPinnedComposites(): ICompositeBarItem[] {
getPinnedComposites(): ICompositeBarModelItem[] {
return this.model.pinnedItems;
}
......@@ -254,7 +264,7 @@ export class CompositeBar extends Widget implements ICompositeBar {
return item && item.activityAction;
}
private computeSizes(items: ICompositeBarItem[]): void {
private computeSizes(items: ICompositeBarModelItem[]): void {
const size = this.options.compositeSize;
if (size) {
items.forEach(composite => this.compositeSizeInBar.set(composite.id, size));
......@@ -379,8 +389,7 @@ export class CompositeBar extends Widget implements ICompositeBar {
this.compositeSwitcherBar.push(this.compositeOverflowAction, { label: false, icon: true });
}
// Persist
this.model.saveState();
this._onDidChange.fire();
}
private getOverflowingComposites(): { id: string, name: string }[] {
......@@ -428,15 +437,7 @@ export class CompositeBar extends Widget implements ICompositeBar {
}
}
interface ISerializedCompositeBarItem {
id: string;
pinned: boolean;
order: number;
visible: boolean;
}
interface ICompositeBarItem extends ISerializedCompositeBarItem {
name: string;
interface ICompositeBarModelItem extends ICompositeBarItem {
activityAction: ActivityAction;
pinnedAction: Action;
activity: ICompositeActivity[];
......@@ -444,28 +445,27 @@ interface ICompositeBarItem extends ISerializedCompositeBarItem {
class CompositeBarModel {
items: ICompositeBarModelItem[];
private readonly options: ICompositeBarOptions;
readonly items: ICompositeBarItem[];
activeItem: ICompositeBarItem;
activeItem: ICompositeBarModelItem;
constructor(
options: ICompositeBarOptions,
private storageService: IStorageService,
items: ICompositeBarItem[],
options: ICompositeBarOptions
) {
this.options = options;
this.items = this.loadItemStates();
this.items = items.map(i => this.createCompositeBarItem(i.id, i.name, i.order, i.pinned, i.visible));
}
get visibleItems(): ICompositeBarItem[] {
get visibleItems(): ICompositeBarModelItem[] {
return this.items.filter(item => item.visible);
}
get pinnedItems(): ICompositeBarItem[] {
get pinnedItems(): ICompositeBarModelItem[] {
return this.items.filter(item => item.visible && item.pinned);
}
private createCompositeBarItem(id: string, name: string, order: number, pinned: boolean, visible: boolean): ICompositeBarItem {
private createCompositeBarItem(id: string, name: string, order: number, pinned: boolean, visible: boolean): ICompositeBarModelItem {
const options = this.options;
return {
id, name, pinned, order, visible,
......@@ -635,7 +635,7 @@ class CompositeBarModel {
return false;
}
findItem(id: string): ICompositeBarItem {
findItem(id: string): ICompositeBarModelItem {
return this.items.filter(item => item.id === id)[0];
}
......@@ -647,17 +647,4 @@ class CompositeBarModel {
}
return -1;
}
private loadItemStates(): ICompositeBarItem[] {
const storedStates = <Array<string | ISerializedCompositeBarItem>>JSON.parse(this.storageService.get(this.options.storageId, StorageScope.GLOBAL, '[]'));
return <ICompositeBarItem[]>storedStates.map(c => {
const serialized: ISerializedCompositeBarItem = typeof c === 'string' /* migration from pinned states to composites states */ ? { id: c, pinned: true, order: void 0, visible: true } : c;
return this.createCompositeBarItem(serialized.id, void 0, serialized.order, serialized.pinned, isUndefinedOrNull(serialized.visible) ? true : serialized.visible);
});
}
saveState(): void {
const serialized = this.items.map(({ id, pinned, order, visible }) => ({ id, pinned, order, visible }));
this.storageService.store(this.options.storageId, JSON.stringify(serialized), StorageScope.GLOBAL);
}
}
......@@ -207,7 +207,7 @@ export class ActivityActionItem extends BaseActionItem {
}));
// Label
this.label = dom.append(this.element, dom.$('a.action-label'));
this.label = dom.append(this.element, dom.$('a'));
// Badge
this.badge = dom.append(this.element, dom.$('.badge'));
......@@ -301,8 +301,9 @@ export class ActivityActionItem extends BaseActionItem {
}
protected updateLabel(): void {
this.label.className = 'action-label';
if (this.activity.cssClass) {
dom.addClasses(this.label, this.activity.cssClass);
dom.addClass(this.label, this.activity.cssClass);
}
if (!this.options.icon) {
this.label.textContent = this.getAction().label;
......@@ -434,7 +435,6 @@ export class CompositeActionItem extends ActivityActionItem {
private static manageExtensionAction: ManageExtensionAction;
private compositeActivity: IActivity;
private cssClass: string;
private compositeTransfer: LocalSelectionTransfer<DraggedCompositeIdentifier>;
constructor(
......@@ -451,7 +451,6 @@ export class CompositeActionItem extends ActivityActionItem {
) {
super(compositeActivityAction, { draggable: true, colors, icon }, themeService);
this.cssClass = compositeActivityAction.class;
this.compositeTransfer = LocalSelectionTransfer.getInstance<DraggedCompositeIdentifier>();
if (!CompositeActionItem.manageExtensionAction) {
......@@ -473,7 +472,7 @@ export class CompositeActionItem extends ActivityActionItem {
this.compositeActivity = {
id: this.compositeActivityAction.activity.id,
cssClass: this.cssClass,
cssClass: this.compositeActivityAction.activity.cssClass,
name: activityName
};
}
......@@ -606,17 +605,6 @@ export class CompositeActionItem extends ActivityActionItem {
this.container.focus();
}
protected updateClass(): void {
if (this.cssClass) {
dom.removeClasses(this.label, this.cssClass);
}
this.cssClass = this.getAction().class;
if (this.cssClass) {
dom.addClasses(this.label, this.cssClass);
}
}
protected updateChecked(): void {
if (this.getAction().checked) {
dom.addClass(this.container, 'checked');
......
......@@ -68,7 +68,7 @@ export abstract class CompositePart<T extends Composite> extends Part {
constructor(
private notificationService: INotificationService,
private storageService: IStorageService,
protected storageService: IStorageService,
private telemetryService: ITelemetryService,
protected contextMenuService: IContextMenuService,
protected partService: IPartService,
......
......@@ -13,7 +13,7 @@ import { CompositePart, ICompositeTitleLabel } from 'vs/workbench/browser/parts/
import { Panel, PanelRegistry, Extensions as PanelExtensions, PanelDescriptor } from 'vs/workbench/browser/panel';
import { IPanelService, IPanelIdentifier } from 'vs/workbench/services/panel/common/panelService';
import { IPartService, Parts, Position } from 'vs/workbench/services/part/common/partService';
import { IStorageService } from 'vs/platform/storage/common/storage';
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
......@@ -30,10 +30,18 @@ import { Dimension, trackFocus } from 'vs/base/browser/dom';
import { localize } from 'vs/nls';
import { IDisposable } from 'vs/base/common/lifecycle';
import { RawContextKey, IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { isUndefinedOrNull } from 'vs/base/common/types';
export const ActivePanelContext = new RawContextKey<string>('activePanel', '');
export const PanelFocusContext = new RawContextKey<boolean>('panelFocus', false);
interface ICachedPanel {
id: string;
pinned: boolean;
order: number;
visible: boolean;
}
export class PanelPart extends CompositePart<Panel> implements IPanelService {
static readonly activePanelSettingsKey = 'workbench.panelpart.activepanelid';
......@@ -81,9 +89,8 @@ export class PanelPart extends CompositePart<Panel> implements IPanelService {
{ hasTitle: true }
);
this.compositeBar = this._register(this.instantiationService.createInstance(CompositeBar, {
this.compositeBar = this._register(this.instantiationService.createInstance(CompositeBar, this.loadCachedPanels(), {
icon: false,
storageId: PanelPart.PINNED_PANELS,
orientation: ActionsOrientation.HORIZONTAL,
openComposite: (compositeId: string) => Promise.resolve(this.openPanel(compositeId, true)),
getActivityAction: (compositeId: string) => this.getCompositeActions(compositeId).activityAction,
......@@ -109,6 +116,8 @@ export class PanelPart extends CompositePart<Panel> implements IPanelService {
})
}));
this._register(this.compositeBar.onDidChange(() => this.saveCachedPanels()));
for (const panel of this.getPanels()) {
this.compositeBar.addComposite(panel);
}
......@@ -206,11 +215,15 @@ export class PanelPart extends CompositePart<Panel> implements IPanelService {
}
getPanels(): PanelDescriptor[] {
return Registry.as<PanelRegistry>(PanelExtensions.Panels).getPanels()
return this.getAllPanels()
.filter(p => p.enabled)
.sort((v1, v2) => v1.order - v2.order);
}
private getAllPanels() {
return Registry.as<PanelRegistry>(PanelExtensions.Panels).getPanels();
}
getPinnedPanels(): PanelDescriptor[] {
const pinnedCompositeIds = this.compositeBar.getPinnedComposites().map(c => c.id);
return this.getPanels()
......@@ -323,6 +336,29 @@ export class PanelPart extends CompositePart<Panel> implements IPanelService {
}
return this.toolBar.getItemsWidth();
}
private saveCachedPanels(): void {
const state: ICachedPanel[] = [];
const compositeItems = this.compositeBar.getComposites();
const allPanels = this.getAllPanels();
for (const compositeItem of compositeItems) {
const panel = allPanels.filter(({ id }) => id === compositeItem.id)[0];
if (panel) {
state.push({ id: panel.id, pinned: compositeItem && compositeItem.pinned, order: compositeItem ? compositeItem.order : void 0, visible: compositeItem && compositeItem.visible });
}
}
this.storageService.store(PanelPart.PINNED_PANELS, JSON.stringify(state), StorageScope.GLOBAL);
}
private loadCachedPanels(): ICachedPanel[] {
const storedStates = <Array<string | ICachedPanel>>JSON.parse(this.storageService.get(PanelPart.PINNED_PANELS, StorageScope.GLOBAL, '[]'));
const cachedPanels = <ICachedPanel[]>storedStates.map(c => {
const serialized: ICachedPanel = typeof c === 'string' /* migration from pinned states to composites states */ ? <ICachedPanel>{ id: c, pinned: true, order: void 0, visible: true } : c;
serialized.visible = isUndefinedOrNull(serialized.visible) ? true : serialized.visible;
return serialized;
});
return cachedPanels;
}
}
registerThemingParticipant((theme: ITheme, collector: ICssStyleCollector) => {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册