From 4e50ae607d4fa59e387a97283c1a2dfb21756149 Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Mon, 24 Sep 2018 11:23:23 -0700 Subject: [PATCH 1/3] Prev/Next Panel item --- .../workbench/browser/parts/compositeBar.ts | 8 +++ .../browser/parts/panel/panelActions.ts | 65 +++++++++++++++++++ .../browser/parts/panel/panelPart.ts | 7 ++ .../services/panel/common/panelService.ts | 7 +- .../progress/test/progressService.test.ts | 4 ++ 5 files changed, 90 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/browser/parts/compositeBar.ts b/src/vs/workbench/browser/parts/compositeBar.ts index f2984c48423..098737bae7e 100644 --- a/src/vs/workbench/browser/parts/compositeBar.ts +++ b/src/vs/workbench/browser/parts/compositeBar.ts @@ -72,6 +72,10 @@ export class CompositeBar extends Widget implements ICompositeBar { return this.model.items; } + getPinnedComposites(): ICompositeBarItem[] { + return this.model.pinnedItems; + } + create(parent: HTMLElement): HTMLElement { const actionBarDiv = parent.appendChild($('.composite-bar')); this.compositeSwitcherBar = this._register(new ActionBar(actionBarDiv, { @@ -460,6 +464,10 @@ class CompositeBarModel { return this.items.filter(item => item.visible); } + get pinnedItems(): ICompositeBarItem[] { + return this.items.filter(item => item.visible && item.pinned); + } + private createCompositeBarItem(id: string, name: string, order: number, pinned: boolean, visible: boolean): ICompositeBarItem { const options = this.options; return { diff --git a/src/vs/workbench/browser/parts/panel/panelActions.ts b/src/vs/workbench/browser/parts/panel/panelActions.ts index 879f869d160..28cca983c57 100644 --- a/src/vs/workbench/browser/parts/panel/panelActions.ts +++ b/src/vs/workbench/browser/parts/panel/panelActions.ts @@ -169,6 +169,69 @@ export class PanelActivityAction extends ActivityAction { } } +export class SwitchPanelItemAction extends Action { + + constructor( + id: string, + name: string, + @IPanelService private panelService: IPanelService + ) { + super(id, name); + } + + run(offset: number): TPromise { + const pinnedPanels = this.panelService.getPinnedPanels(); + const activePanel = this.panelService.getActivePanel(); + if (!activePanel) { + return TPromise.as(null); + } + let targetPanelId: string; + for (let i = 0; i < pinnedPanels.length; i++) { + if (pinnedPanels[i].id === activePanel.getId()) { + targetPanelId = pinnedPanels[(i + pinnedPanels.length + offset) % pinnedPanels.length].id; + break; + } + } + return this.panelService.openPanel(targetPanelId, true); + } +} + +export class PreviousPanelViewAction extends SwitchPanelItemAction { + + static readonly ID = 'workbench.action.previousPanelView'; + static LABEL = nls.localize('previousPanelView', 'Previous Panel View'); + + constructor( + id: string, + name: string, + @IPanelService panelService: IPanelService + ) { + super(id, name, panelService); + } + + run(): TPromise { + return super.run(-1); + } +} + +export class NextPanelViewAction extends SwitchPanelItemAction { + + static readonly ID = 'workbench.action.nextPanelView'; + static LABEL = nls.localize('nextPanelView', 'Next Panel View'); + + constructor( + id: string, + name: string, + @IPanelService panelService: IPanelService + ) { + super(id, name, panelService); + } + + public run(): TPromise { + return super.run(1); + } +} + const actionRegistry = Registry.as(WorkbenchExtensions.WorkbenchActions); actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(TogglePanelAction, TogglePanelAction.ID, TogglePanelAction.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.KEY_J }), 'View: Toggle Panel', nls.localize('view', "View")); actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(FocusPanelAction, FocusPanelAction.ID, FocusPanelAction.LABEL), 'View: Focus into Panel', nls.localize('view', "View")); @@ -176,6 +239,8 @@ actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ToggleMaximizedP actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ClosePanelAction, ClosePanelAction.ID, ClosePanelAction.LABEL), 'View: Close Panel', nls.localize('view', "View")); actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(TogglePanelPositionAction, TogglePanelPositionAction.ID, TogglePanelPositionAction.LABEL), 'View: Toggle Panel Position', nls.localize('view', "View")); actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ToggleMaximizedPanelAction, ToggleMaximizedPanelAction.ID, undefined), 'View: Toggle Panel Position', nls.localize('view', "View")); +actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(PreviousPanelViewAction, PreviousPanelViewAction.ID, PreviousPanelViewAction.LABEL), 'View: Open Previous Panel View', nls.localize('view', "View")); +actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(NextPanelViewAction, NextPanelViewAction.ID, NextPanelViewAction.LABEL), 'View: Open Next Panel View', nls.localize('view', "View")); MenuRegistry.appendMenuItem(MenuId.MenubarAppearanceMenu, { group: '2_workbench_layout', diff --git a/src/vs/workbench/browser/parts/panel/panelPart.ts b/src/vs/workbench/browser/parts/panel/panelPart.ts index d79b236141e..6b2332052da 100644 --- a/src/vs/workbench/browser/parts/panel/panelPart.ts +++ b/src/vs/workbench/browser/parts/panel/panelPart.ts @@ -198,6 +198,13 @@ export class PanelPart extends CompositePart implements IPanelService { .sort((v1, v2) => v1.order - v2.order); } + getPinnedPanels(): PanelDescriptor[] { + const pinnedCompositeIds = this.compositeBar.getPinnedComposites().map(c => c.id); + return this.getPanels() + .filter(p => pinnedCompositeIds.indexOf(p.id) !== -1) + .sort((p1, p2) => pinnedCompositeIds.indexOf(p1.id) - pinnedCompositeIds.indexOf(p2.id)); + } + setPanelEnablement(id: string, enabled: boolean): void { const descriptor = Registry.as(PanelExtensions.Panels).getPanels().filter(p => p.id === id).pop(); if (descriptor && descriptor.enabled !== enabled) { diff --git a/src/vs/workbench/services/panel/common/panelService.ts b/src/vs/workbench/services/panel/common/panelService.ts index 97179ea7bb8..6d73423c591 100644 --- a/src/vs/workbench/services/panel/common/panelService.ts +++ b/src/vs/workbench/services/panel/common/panelService.ts @@ -34,10 +34,15 @@ export interface IPanelService { getActivePanel(): IPanel; /** - * Returns all enabled panels + * * Returns all built-in panels following the default order (Problems - Output - Debug Console - Terminal) */ getPanels(): IPanelIdentifier[]; + /** + * Returns pinned panels following the visual order + */ + getPinnedPanels(): IPanelIdentifier[]; + /** * Enables or disables a panel. Disabled panels are completly hidden from UI. * By default all panels are enabled. diff --git a/src/vs/workbench/services/progress/test/progressService.test.ts b/src/vs/workbench/services/progress/test/progressService.test.ts index e81c13a61db..00c3b62b128 100644 --- a/src/vs/workbench/services/progress/test/progressService.test.ts +++ b/src/vs/workbench/services/progress/test/progressService.test.ts @@ -79,6 +79,10 @@ class TestPanelService implements IPanelService { return []; } + public getPinnedPanels(): any[] { + return []; + } + public getActivePanel(): IViewlet { return activeViewlet; } From 8869632ba20473f1e795c1217aab4caf7875ce21 Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Mon, 24 Sep 2018 14:34:36 -0700 Subject: [PATCH 2/3] Prev/Next Sidebar View --- .../parts/activitybar/activitybarActions.ts | 108 +++++++++++++++--- .../parts/activitybar/activitybarPart.ts | 8 +- .../browser/parts/panel/panelActions.ts | 6 +- .../workbench/electron-browser/workbench.ts | 2 +- .../activity/browser/activityService.ts | 5 + .../services/activity/common/activity.ts | 5 + .../services/viewlet/browser/viewlet.ts | 2 +- 7 files changed, 113 insertions(+), 23 deletions(-) diff --git a/src/vs/workbench/browser/parts/activitybar/activitybarActions.ts b/src/vs/workbench/browser/parts/activitybar/activitybarActions.ts index 1ab2e743b9e..592230a3491 100644 --- a/src/vs/workbench/browser/parts/activitybar/activitybarActions.ts +++ b/src/vs/workbench/browser/parts/activitybar/activitybarActions.ts @@ -5,26 +5,31 @@ 'use strict'; -import 'vs/css!./media/activityaction'; import * as DOM from 'vs/base/browser/dom'; -import { EventType as TouchEventType, GestureEvent } from 'vs/base/browser/touch'; -import { TPromise } from 'vs/base/common/winjs.base'; -import { Action } from 'vs/base/common/actions'; -import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; -import { ViewletDescriptor } from 'vs/workbench/browser/viewlet'; -import { IActivity, IGlobalActivity } from 'vs/workbench/common/activity'; -import { dispose } from 'vs/base/common/lifecycle'; -import { IViewletService, } from 'vs/workbench/services/viewlet/browser/viewlet'; -import { IPartService, Parts } from 'vs/workbench/services/part/common/partService'; -import { IThemeService, ITheme, registerThemingParticipant, ICssStyleCollector } from 'vs/platform/theme/common/themeService'; -import { activeContrastBorder, focusBorder } from 'vs/platform/theme/common/colorRegistry'; -import { StandardMouseEvent } from 'vs/base/browser/mouseEvent'; -import { KeyCode } from 'vs/base/common/keyCodes'; import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent'; -import { ActivityAction, ActivityActionItem, ICompositeBarColors, ToggleCompositePinnedAction, ICompositeBar } from 'vs/workbench/browser/parts/compositeBarActions'; -import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; +import { StandardMouseEvent } from 'vs/base/browser/mouseEvent'; +import { EventType as TouchEventType, GestureEvent } from 'vs/base/browser/touch'; +import { Action } from 'vs/base/common/actions'; +import { KeyCode } from 'vs/base/common/keyCodes'; +import { dispose } from 'vs/base/common/lifecycle'; import { URI } from 'vs/base/common/uri'; +import { TPromise } from 'vs/base/common/winjs.base'; +import 'vs/css!./media/activityaction'; +import * as nls from 'vs/nls'; +import { SyncActionDescriptor } from 'vs/platform/actions/common/actions'; +import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; +import { Registry } from 'vs/platform/registry/common/platform'; +import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; +import { activeContrastBorder, focusBorder } from 'vs/platform/theme/common/colorRegistry'; +import { ICssStyleCollector, ITheme, IThemeService, registerThemingParticipant } from 'vs/platform/theme/common/themeService'; +import { ActivityAction, ActivityActionItem, ICompositeBar, ICompositeBarColors, ToggleCompositePinnedAction } from 'vs/workbench/browser/parts/compositeBarActions'; +import { ViewletDescriptor } from 'vs/workbench/browser/viewlet'; +import { Extensions as ActionExtensions, IWorkbenchActionRegistry } from 'vs/workbench/common/actions'; +import { IActivity, IGlobalActivity } from 'vs/workbench/common/activity'; import { ACTIVITY_BAR_FOREGROUND } from 'vs/workbench/common/theme'; +import { IActivityService } from 'vs/workbench/services/activity/common/activity'; +import { IPartService, Parts } from 'vs/workbench/services/part/common/partService'; +import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet'; export class ViewletActivityAction extends ActivityAction { @@ -191,6 +196,77 @@ export class PlaceHolderToggleCompositePinnedAction extends ToggleCompositePinne } } +class SwitchSidebarViewAction extends Action { + + constructor( + id: string, + name: string, + @IViewletService private viewletService: IViewletService, + @IActivityService private activityService: IActivityService + ) { + super(id, name); + } + + run(offset: number): TPromise { + const pinnedViewletIds = this.activityService.getPinnedViewletIds(); + + const activeViewlet = this.viewletService.getActiveViewlet(); + if (!activeViewlet) { + return TPromise.as(null); + } + let targetViewletId: string; + for (let i = 0; i < pinnedViewletIds.length; i++) { + if (pinnedViewletIds[i] === activeViewlet.getId()) { + targetViewletId = pinnedViewletIds[(i + pinnedViewletIds.length + offset) % pinnedViewletIds.length]; + break; + } + } + return this.viewletService.openViewlet(targetViewletId, true); + } +} + +export class PreviousSidebarViewAction extends SwitchSidebarViewAction { + + static readonly ID = 'workbench.action.previousSidebarView'; + static LABEL = nls.localize('previousSidebarView', 'Previous Sidebar View'); + + constructor( + id: string, + name: string, + @IViewletService viewletService: IViewletService, + @IActivityService activityService: IActivityService + ) { + super(id, name, viewletService, activityService); + } + + run(): TPromise { + return super.run(-1); + } +} + +export class NextSidebarViewAction extends SwitchSidebarViewAction { + + static readonly ID = 'workbench.action.nextSidebarView'; + static LABEL = nls.localize('nextSidebarView', 'Next Sidebar View'); + + constructor( + id: string, + name: string, + @IViewletService viewletService: IViewletService, + @IActivityService activityService: IActivityService + ) { + super(id, name, viewletService, activityService); + } + + run(): TPromise { + return super.run(1); + } +} + +const registry = Registry.as(ActionExtensions.WorkbenchActions); +registry.registerWorkbenchAction(new SyncActionDescriptor(PreviousSidebarViewAction, PreviousSidebarViewAction.ID, PreviousSidebarViewAction.LABEL), 'View: Open Previous Sidebar View', nls.localize('view', "View")); +registry.registerWorkbenchAction(new SyncActionDescriptor(NextSidebarViewAction, NextSidebarViewAction.ID, NextSidebarViewAction.LABEL), 'View: Open Next Sidebar View', nls.localize('view', "View")); + registerThemingParticipant((theme: ITheme, collector: ICssStyleCollector) => { const activeForegroundColor = theme.getColor(ACTIVITY_BAR_FOREGROUND); diff --git a/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts b/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts index 4ef749c3fda..74b9dc71297 100644 --- a/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts +++ b/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts @@ -306,8 +306,12 @@ export class ActivitybarPart extends Part { } } - getPinned(): string[] { - return this.viewletService.getViewlets().map(v => v.id).filter(id => this.compositeBar.isPinned(id)); + getPinnedViewletIds(): string[] { + const pinnedCompositeIds = this.compositeBar.getPinnedComposites().map(v => v.id); + return this.viewletService.getViewlets() + .filter(v => this.compositeBar.isPinned(v.id)) + .sort((v1, v2) => pinnedCompositeIds.indexOf(v1.id) - pinnedCompositeIds.indexOf(v2.id)) + .map(v => v.id); } layout(dimension: Dimension): Dimension[] { diff --git a/src/vs/workbench/browser/parts/panel/panelActions.ts b/src/vs/workbench/browser/parts/panel/panelActions.ts index 28cca983c57..34582928dec 100644 --- a/src/vs/workbench/browser/parts/panel/panelActions.ts +++ b/src/vs/workbench/browser/parts/panel/panelActions.ts @@ -169,7 +169,7 @@ export class PanelActivityAction extends ActivityAction { } } -export class SwitchPanelItemAction extends Action { +export class SwitchPanelViewAction extends Action { constructor( id: string, @@ -196,7 +196,7 @@ export class SwitchPanelItemAction extends Action { } } -export class PreviousPanelViewAction extends SwitchPanelItemAction { +export class PreviousPanelViewAction extends SwitchPanelViewAction { static readonly ID = 'workbench.action.previousPanelView'; static LABEL = nls.localize('previousPanelView', 'Previous Panel View'); @@ -214,7 +214,7 @@ export class PreviousPanelViewAction extends SwitchPanelItemAction { } } -export class NextPanelViewAction extends SwitchPanelItemAction { +export class NextPanelViewAction extends SwitchPanelViewAction { static readonly ID = 'workbench.action.nextPanelView'; static LABEL = nls.localize('nextPanelView', 'Next Panel View'); diff --git a/src/vs/workbench/electron-browser/workbench.ts b/src/vs/workbench/electron-browser/workbench.ts index 2952ac488fe..9b322ad8934 100644 --- a/src/vs/workbench/electron-browser/workbench.ts +++ b/src/vs/workbench/electron-browser/workbench.ts @@ -762,7 +762,7 @@ export class Workbench extends Disposable implements IPartService { return { customKeybindingsCount: this.keybindingService.customKeybindingsCount(), - pinnedViewlets: this.activitybarPart.getPinned(), + pinnedViewlets: this.activitybarPart.getPinnedViewletIds(), restoredViewlet: viewletIdToRestore, restoredEditorsCount: this.editorService.visibleEditors.length }; diff --git a/src/vs/workbench/services/activity/browser/activityService.ts b/src/vs/workbench/services/activity/browser/activityService.ts index 27bbe40af63..f230d4a2303 100644 --- a/src/vs/workbench/services/activity/browser/activityService.ts +++ b/src/vs/workbench/services/activity/browser/activityService.ts @@ -28,4 +28,9 @@ export class ActivityService implements IActivityService { return this.activitybarPart.showActivity(compositeOrActionId, badge, clazz, priority); } + + getPinnedViewletIds(): string[] { + return this.activitybarPart.getPinnedViewletIds(); + } + } diff --git a/src/vs/workbench/services/activity/common/activity.ts b/src/vs/workbench/services/activity/common/activity.ts index 27513b65417..06d2d83edd7 100644 --- a/src/vs/workbench/services/activity/common/activity.ts +++ b/src/vs/workbench/services/activity/common/activity.ts @@ -67,4 +67,9 @@ export interface IActivityService { * Show activity in the panel for the given panel or in the activitybar for the given viewlet or global action. */ showActivity(compositeOrActionId: string, badge: IBadge, clazz?: string, priority?: number): IDisposable; + + /** + * Returns id of pinned viewlets following the visual order + */ + getPinnedViewletIds(): string[]; } diff --git a/src/vs/workbench/services/viewlet/browser/viewlet.ts b/src/vs/workbench/services/viewlet/browser/viewlet.ts index a6903bb9fb9..1f0b49bb12f 100644 --- a/src/vs/workbench/services/viewlet/browser/viewlet.ts +++ b/src/vs/workbench/services/viewlet/browser/viewlet.ts @@ -42,7 +42,7 @@ export interface IViewletService { getViewlet(id: string): ViewletDescriptor; /** - * Returns all viewlets + * Returns all enabled viewlets following the default order (Explorer - Search - SCM - Debug - Extensions) */ getAllViewlets(): ViewletDescriptor[]; From 660209ca74f63033ea013d42dfc34954e8cee1c8 Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Mon, 24 Sep 2018 14:36:39 -0700 Subject: [PATCH 3/3] Import order --- .../workbench/browser/parts/activitybar/activitybarActions.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/browser/parts/activitybar/activitybarActions.ts b/src/vs/workbench/browser/parts/activitybar/activitybarActions.ts index 592230a3491..ec9b4b364e7 100644 --- a/src/vs/workbench/browser/parts/activitybar/activitybarActions.ts +++ b/src/vs/workbench/browser/parts/activitybar/activitybarActions.ts @@ -5,6 +5,8 @@ 'use strict'; +import 'vs/css!./media/activityaction'; +import * as nls from 'vs/nls'; import * as DOM from 'vs/base/browser/dom'; import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent'; import { StandardMouseEvent } from 'vs/base/browser/mouseEvent'; @@ -14,8 +16,6 @@ import { KeyCode } from 'vs/base/common/keyCodes'; import { dispose } from 'vs/base/common/lifecycle'; import { URI } from 'vs/base/common/uri'; import { TPromise } from 'vs/base/common/winjs.base'; -import 'vs/css!./media/activityaction'; -import * as nls from 'vs/nls'; import { SyncActionDescriptor } from 'vs/platform/actions/common/actions'; import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; import { Registry } from 'vs/platform/registry/common/platform';