diff --git a/src/vs/workbench/browser/parts/activitybar/activitybarActions.ts b/src/vs/workbench/browser/parts/activitybar/activitybarActions.ts index c2440a2bb94..8df90240983 100644 --- a/src/vs/workbench/browser/parts/activitybar/activitybarActions.ts +++ b/src/vs/workbench/browser/parts/activitybar/activitybarActions.ts @@ -4,24 +4,30 @@ *--------------------------------------------------------------------------------------------*/ 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'; import { EventType as TouchEventType, GestureEvent } from 'vs/base/browser/touch'; 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 { dispose } from 'vs/base/common/lifecycle'; import { URI } from 'vs/base/common/uri'; +import { TPromise } from 'vs/base/common/winjs.base'; +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 { @@ -188,6 +194,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 eb96558d29e..052bd0252d5 100644 --- a/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts +++ b/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts @@ -304,8 +304,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/compositeBar.ts b/src/vs/workbench/browser/parts/compositeBar.ts index c8811bcce21..93f55214716 100644 --- a/src/vs/workbench/browser/parts/compositeBar.ts +++ b/src/vs/workbench/browser/parts/compositeBar.ts @@ -70,6 +70,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, { @@ -458,6 +462,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 53cd2e76c1e..8adb4ef55d7 100644 --- a/src/vs/workbench/browser/parts/panel/panelActions.ts +++ b/src/vs/workbench/browser/parts/panel/panelActions.ts @@ -179,6 +179,69 @@ export class PanelActivityAction extends ActivityAction { } } +export class SwitchPanelViewAction 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 SwitchPanelViewAction { + + 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 SwitchPanelViewAction { + + 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")); @@ -186,6 +249,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/electron-browser/workbench.ts b/src/vs/workbench/electron-browser/workbench.ts index 351a26ae6f2..8c26181539c 100644 --- a/src/vs/workbench/electron-browser/workbench.ts +++ b/src/vs/workbench/electron-browser/workbench.ts @@ -767,7 +767,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 66318fb85a4..7afc6e1fe08 100644 --- a/src/vs/workbench/services/activity/browser/activityService.ts +++ b/src/vs/workbench/services/activity/browser/activityService.ts @@ -26,4 +26,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 ae5bde68828..519a5814136 100644 --- a/src/vs/workbench/services/activity/common/activity.ts +++ b/src/vs/workbench/services/activity/common/activity.ts @@ -65,4 +65,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/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 608c9062962..042124c3824 100644 --- a/src/vs/workbench/services/progress/test/progressService.test.ts +++ b/src/vs/workbench/services/progress/test/progressService.test.ts @@ -77,6 +77,10 @@ class TestPanelService implements IPanelService { return []; } + public getPinnedPanels(): any[] { + return []; + } + public getActivePanel(): IViewlet { return activeViewlet; } diff --git a/src/vs/workbench/services/viewlet/browser/viewlet.ts b/src/vs/workbench/services/viewlet/browser/viewlet.ts index 2f5b5ef25ed..7ae5e2acc4f 100644 --- a/src/vs/workbench/services/viewlet/browser/viewlet.ts +++ b/src/vs/workbench/services/viewlet/browser/viewlet.ts @@ -40,7 +40,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[];