This commit is contained in:
Sandeep Somavarapu 2018-08-22 16:49:49 +02:00
parent 07c6df15a4
commit f08007bf9d
8 changed files with 117 additions and 92 deletions

View file

@ -94,6 +94,7 @@ class ViewsContainersExtensionHandler implements IWorkbenchContribution {
}
private handleAndRegisterCustomViewContainers() {
let order = TEST_VIEW_CONTAINER_ORDER + 1;
viewsContainersExtensionPoint.setHandler((extensions) => {
for (let extension of extensions) {
const { value, collector } = extension;
@ -103,7 +104,7 @@ class ViewsContainersExtensionHandler implements IWorkbenchContribution {
}
switch (entry.key) {
case 'activitybar':
this.registerCustomViewContainers(entry.value, extension.description);
order = this.registerCustomViewContainers(entry.value, extension.description, order);
break;
}
});
@ -139,12 +140,13 @@ class ViewsContainersExtensionHandler implements IWorkbenchContribution {
return true;
}
private registerCustomViewContainers(containers: IUserFriendlyViewsContainerDescriptor[], extension: IExtensionDescription) {
containers.forEach((descriptor, index) => {
private registerCustomViewContainers(containers: IUserFriendlyViewsContainerDescriptor[], extension: IExtensionDescription, order: number): number {
containers.forEach(descriptor => {
const cssClass = `extensionViewlet-${descriptor.id}`;
const icon = resources.joinPath(extension.extensionLocation, descriptor.icon);
this.registerCustomViewlet({ id: `workbench.view.extension.${descriptor.id}`, title: descriptor.title, icon }, TEST_VIEW_CONTAINER_ORDER + index + 1, cssClass, extension.id);
this.registerCustomViewlet({ id: `workbench.view.extension.${descriptor.id}`, title: descriptor.title, icon }, order++, cssClass, extension.id);
});
return order;
}
private registerCustomViewlet(descriptor: IUserFriendlyViewsContainerDescriptor2, order: number, cssClass: string, extensionId: string): void {

View file

@ -87,20 +87,15 @@ export class ActivitybarPart extends Part {
overflowActionSize: ActivitybarPart.ACTION_HEIGHT
}));
const previousState = this.storageService.get(ActivitybarPart.PLACEHOLDER_VIEWLETS, StorageScope.GLOBAL, void 0);
if (previousState) {
let parsedPreviousState = <IPlaceholderComposite[]>JSON.parse(previousState);
parsedPreviousState.forEach((s) => {
if (typeof s.iconUrl === 'object') {
s.iconUrl = URI.revive(s.iconUrl);
} else {
s.iconUrl = void 0;
}
});
this.placeholderComposites = parsedPreviousState;
} else {
this.placeholderComposites = this.compositeBar.getCompositesFromStorage().map(id => (<IPlaceholderComposite>{ id, iconUrl: void 0 }));
}
const previousState = this.storageService.get(ActivitybarPart.PLACEHOLDER_VIEWLETS, StorageScope.GLOBAL, '[]');
this.placeholderComposites = <IPlaceholderComposite[]>JSON.parse(previousState);
this.placeholderComposites.forEach((s) => {
if (typeof s.iconUrl === 'object') {
s.iconUrl = URI.revive(s.iconUrl);
} else {
s.iconUrl = void 0;
}
});
this.registerListeners();
this.updateCompositebar();
@ -119,7 +114,7 @@ export class ActivitybarPart extends Part {
if (enabled) {
this.compositeBar.addComposite(this.viewletService.getViewlet(id));
} else {
this.removeComposite(id);
this.removeComposite(id, true);
}
}));
@ -127,7 +122,7 @@ export class ActivitybarPart extends Part {
}
private onDidRegisterExtensions(): void {
this.removeNotExistingPlaceholderComposites();
this.removeNotExistingComposites();
this.updateCompositebar();
}
@ -283,17 +278,21 @@ export class ActivitybarPart extends Part {
}
}
private removeNotExistingPlaceholderComposites(): void {
const viewlets = this.viewletService.getViewlets();
private removeNotExistingComposites(): void {
const viewlets = this.viewletService.getAllViewlets();
for (const { id } of this.placeholderComposites) {
if (viewlets.every(viewlet => viewlet.id !== id)) {
this.removeComposite(id);
this.removeComposite(id, false);
}
}
}
private removeComposite(compositeId: string): void {
this.compositeBar.removeComposite(compositeId);
private removeComposite(compositeId: string, hide: boolean): void {
if (hide) {
this.compositeBar.hideComposite(compositeId);
} else {
this.compositeBar.removeComposite(compositeId);
}
const compositeActions = this.compositeActions[compositeId];
if (compositeActions) {
compositeActions.activityAction.dispose();
@ -337,7 +336,7 @@ export class ActivitybarPart extends Part {
}
shutdown(): void {
const state = this.viewletService.getViewlets().map(viewlet => ({ id: viewlet.id, iconUrl: viewlet.iconUrl }));
const state = this.viewletService.getAllViewlets().map(({ id, iconUrl }) => ({ id, iconUrl }));
this.storageService.store(ActivitybarPart.PLACEHOLDER_VIEWLETS, JSON.stringify(state), StorageScope.GLOBAL);
super.shutdown();

View file

@ -20,6 +20,7 @@ import { Dimension, $, addDisposableListener, EventType, EventHelper } from 'vs/
import { StandardMouseEvent } from 'vs/base/browser/mouseEvent';
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
import { Widget } from 'vs/base/browser/ui/widget';
import { isUndefinedOrNull } from 'vs/base/common/types';
export interface ICompositeBarOptions {
icon: boolean;
@ -46,28 +47,22 @@ export class CompositeBar extends Widget implements ICompositeBar {
private compositeOverflowActionItem: CompositeOverflowActivityActionItem;
private model: CompositeBarModel;
private storedState: ISerializedCompositeBarItem[];
private visibleComposites: string[];
private compositeSizeInBar: Map<string, number>;
constructor(
private options: ICompositeBarOptions,
@IInstantiationService private instantiationService: IInstantiationService,
@IStorageService private storageService: IStorageService,
@IStorageService storageService: IStorageService,
@IContextMenuService private contextMenuService: IContextMenuService
) {
super();
this.model = new CompositeBarModel(options);
this.storedState = this.loadCompositeItemsFromStorage();
this.model = new CompositeBarModel(options, storageService);
this.visibleComposites = [];
this.compositeSizeInBar = new Map<string, number>();
}
getCompositesFromStorage(): string[] {
return this.storedState.map(s => s.id);
}
create(parent: HTMLElement): HTMLElement {
const actionBarDiv = parent.appendChild($('.composite-bar'));
this.compositeSwitcherBar = this._register(new ActionBar(actionBarDiv, {
@ -93,7 +88,7 @@ export class CompositeBar extends Widget implements ICompositeBar {
EventHelper.stop(e, true);
CompositeActionItem.clearDraggedComposite();
const targetItem = this.model.items[this.model.items.length - 1];
const targetItem = this.model.visibleItems[this.model.visibleItems.length - 1];
if (targetItem && targetItem.id !== draggedCompositeId) {
this.move(draggedCompositeId, targetItem.id);
}
@ -113,38 +108,17 @@ export class CompositeBar extends Widget implements ICompositeBar {
if (this.compositeSizeInBar.size === 0) {
// Compute size of each composite by getting the size from the css renderer
// Size is later used for overflow computation
this.computeSizes(this.model.items);
this.computeSizes(this.model.visibleItems);
}
this.updateCompositeSwitcher();
}
addComposite({ id, name, order }: { id: string; name: string, order: number }): void {
const state = this.storedState.filter(s => s.id === id)[0];
const pinned = state ? state.pinned : true;
let index = order >= 0 ? order : this.model.items.length;
if (state) {
// Find the index by looking its previous item
index = 0;
for (let i = this.storedState.indexOf(state) - 1; i >= 0; i--) {
const previousItemId = this.storedState[i].id;
const previousItemIndex = this.model.findIndex(previousItemId);
if (previousItemIndex !== -1) {
index = previousItemIndex + 1;
break;
}
}
}
// Add to the model
if (this.model.add(id, name, order, index)) {
if (this.model.add(id, name, order)) {
this.computeSizes([this.model.findItem(id)]);
if (pinned) {
this.pin(id);
} else {
this.updateCompositeSwitcher();
}
this.updateCompositeSwitcher();
}
}
@ -161,6 +135,12 @@ export class CompositeBar extends Widget implements ICompositeBar {
}
}
hideComposite(id: string): void {
if (this.model.hide(id)) {
this.updateCompositeSwitcher();
}
}
activateComposite(id: string): void {
const previousActiveItem = this.model.activeItem;
if (this.model.activate(id)) {
@ -282,7 +262,7 @@ export class CompositeBar extends Widget implements ICompositeBar {
return; // We have not been rendered yet so there is nothing to update.
}
let compositesToShow = this.model.items.filter(item =>
let compositesToShow = this.model.visibleItems.filter(item =>
item.pinned
|| (this.model.activeItem && this.model.activeItem.id === item.id) /* Show the active composite even if it is not pinned */
).map(item => item.id);
@ -385,11 +365,11 @@ export class CompositeBar extends Widget implements ICompositeBar {
}
// Persist
this.saveCompositeItems();
this.model.saveState();
}
private getOverflowingComposites(): { id: string, name: string }[] {
let overflowingIds = this.model.items.filter(item => item.pinned).map(item => item.id);
let overflowingIds = this.model.visibleItems.filter(item => item.pinned).map(item => item.id);
// Show the active composite even if it is not pinned
if (this.model.activeItem && !this.model.activeItem.pinned) {
@ -397,13 +377,13 @@ export class CompositeBar extends Widget implements ICompositeBar {
}
overflowingIds = overflowingIds.filter(compositeId => this.visibleComposites.indexOf(compositeId) === -1);
return this.model.items.filter(c => overflowingIds.indexOf(c.id) !== -1);
return this.model.visibleItems.filter(c => overflowingIds.indexOf(c.id) !== -1);
}
private showContextMenu(e: MouseEvent): void {
EventHelper.stop(e, true);
const event = new StandardMouseEvent(e);
const actions: IAction[] = this.model.items
const actions: IAction[] = this.model.visibleItems
.map(({ id, name, activityAction }) => (<IAction>{
id,
label: name,
@ -427,24 +407,13 @@ export class CompositeBar extends Widget implements ICompositeBar {
getActions: () => TPromise.as(actions),
});
}
private loadCompositeItemsFromStorage(): ISerializedCompositeBarItem[] {
const storedStates = <Array<string | ISerializedCompositeBarItem>>JSON.parse(this.storageService.get(this.options.storageId, StorageScope.GLOBAL, '[]'));
const compositeStates = <ISerializedCompositeBarItem[]>storedStates.map(c =>
typeof c === 'string' /* migration from pinned states to composites states */ ? { id: c, pinned: true } : c);
return compositeStates;
}
private saveCompositeItems(): void {
this.storedState = this.model.toJSON();
this.storageService.store(this.options.storageId, JSON.stringify(this.storedState), StorageScope.GLOBAL);
}
}
interface ISerializedCompositeBarItem {
id: string;
pinned: boolean;
order: number;
visible: boolean;
}
interface ICompositeBarItem extends ISerializedCompositeBarItem {
@ -456,15 +425,28 @@ interface ICompositeBarItem extends ISerializedCompositeBarItem {
class CompositeBarModel {
readonly items: ICompositeBarItem[] = [];
private readonly options: ICompositeBarOptions;
readonly items: ICompositeBarItem[];
activeItem: ICompositeBarItem;
constructor(private options: ICompositeBarOptions) { }
constructor(
options: ICompositeBarOptions,
private storageService: IStorageService,
) {
this.options = options;
this.items = this.loadItemStates();
}
private createCompositeBarItem(id: string, name: string, order: number, pinned: boolean): ICompositeBarItem {
get visibleItems(): ICompositeBarItem[] {
return this.items.filter(item => item.visible);
}
private createCompositeBarItem(id: string, name: string, order: number, pinned: boolean, visible: boolean): ICompositeBarItem {
const options = this.options;
return {
id, name, pinned, order, activity: [],
id, name, pinned, order, visible,
activity: [],
get activityAction() {
return options.getActivityAction(id);
},
@ -474,20 +456,31 @@ class CompositeBarModel {
};
}
add(id: string, name: string, order: number, index: number): boolean {
add(id: string, name: string, order: number): boolean {
const item = this.findItem(id);
if (item) {
item.order = order;
let changed = false;
item.name = name;
return false;
if (!isUndefinedOrNull(order)) {
changed = item.order !== order;
item.order = order;
}
if (!item.visible) {
item.visible = true;
changed = true;
}
return changed;
} else {
if (index === void 0) {
index = 0;
const item = this.createCompositeBarItem(id, name, order, false, true);
if (isUndefinedOrNull(order)) {
this.items.push(item);
} else {
let index = 0;
while (index < this.items.length && this.items[index].order < order) {
index++;
}
this.items.splice(index, 0, item);
}
this.items.splice(index, 0, this.createCompositeBarItem(id, name, order, false));
return true;
}
}
@ -502,6 +495,19 @@ class CompositeBarModel {
return false;
}
hide(id: string): boolean {
for (const item of this.items) {
if (item.id === id) {
if (item.visible) {
item.visible = false;
return true;
}
return false;
}
}
return false;
}
move(compositeId: string, toCompositeId: string): boolean {
const fromIndex = this.findIndex(compositeId);
@ -610,7 +616,7 @@ class CompositeBarModel {
return this.items.filter(item => item.id === id)[0];
}
findIndex(id: string): number {
private findIndex(id: string): number {
for (let index = 0; index < this.items.length; index++) {
if (this.items[index].id === id) {
return index;
@ -619,7 +625,16 @@ class CompositeBarModel {
return -1;
}
toJSON(): ISerializedCompositeBarItem[] {
return this.items.map(({ id, pinned, order }) => ({ id, pinned, order }));
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);
}
}

View file

@ -281,7 +281,7 @@ export class PanelPart extends CompositePart<Panel> implements IPanelService {
}
private removeComposite(compositeId: string): void {
this.compositeBar.removeComposite(compositeId);
this.compositeBar.hideComposite(compositeId);
const compositeActions = this.compositeActions[compositeId];
if (compositeActions) {
compositeActions.activityAction.dispose();

View file

@ -496,7 +496,7 @@ export class ViewsService extends Disposable implements IViewsService {
const viewContainersRegistry = Registry.as<IViewContainersRegistry>(ViewContainerExtensions.ViewContainersRegistry);
viewContainersRegistry.all.forEach(viewContainer => this.onDidRegisterViewContainer(viewContainer));
this._register(viewContainersRegistry.onDidRegister(viewContainer => this.onDidRegisterViewContainer(viewContainer)));
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 !== TEST_VIEW_CONTAINER_ID))));
this._register(Registry.as<ViewletRegistry>(ViewletExtensions.Viewlets).onDidRegister(viewlet => this.viewletService.setViewletEnablement(viewlet.id, this.storageService.getBoolean(`viewservice.${viewlet.id}.enablement`, StorageScope.WORKSPACE, viewlet.id !== TEST_VIEW_CONTAINER_ID))));
}
openView(id: string, focus: boolean): TPromise<IView> {

View file

@ -40,6 +40,10 @@ class TestViewletService implements IViewletService {
return [];
}
public getAllViewlets(): ViewletDescriptor[] {
return [];
}
public getActiveViewlet(): IViewlet {
return activeViewlet;
}

View file

@ -41,6 +41,11 @@ export interface IViewletService {
*/
getViewlet(id: string): ViewletDescriptor;
/**
* Returns all viewlets
*/
getAllViewlets(): ViewletDescriptor[];
/**
* Returns all enabled viewlets
*/

View file

@ -92,7 +92,7 @@ export class ViewletService extends Disposable implements IViewletService {
.filter(v => v.enabled);
}
private getAllViewlets(): ViewletDescriptor[] {
getAllViewlets(): ViewletDescriptor[] {
return this.viewletRegistry.getViewlets()
.sort((v1, v2) => v1.order - v2.order);
}