Skip to content

Commit 2afc872

Browse files
authored
Merge pull request microsoft#59270 from Microsoft/octref/44625
Prev/Next Panel/Sidebar view. Part of microsoft#44625
2 parents 53e166f + 660209c commit 2afc872

11 files changed

Lines changed: 196 additions & 16 deletions

File tree

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

Lines changed: 88 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,24 +4,30 @@
44
*--------------------------------------------------------------------------------------------*/
55

66
import 'vs/css!./media/activityaction';
7+
import * as nls from 'vs/nls';
78
import * as DOM from 'vs/base/browser/dom';
9+
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
10+
import { StandardMouseEvent } from 'vs/base/browser/mouseEvent';
811
import { EventType as TouchEventType, GestureEvent } from 'vs/base/browser/touch';
912
import { Action } from 'vs/base/common/actions';
13+
import { KeyCode } from 'vs/base/common/keyCodes';
14+
import { dispose } from 'vs/base/common/lifecycle';
15+
import { URI } from 'vs/base/common/uri';
16+
import { TPromise } from 'vs/base/common/winjs.base';
17+
import { SyncActionDescriptor } from 'vs/platform/actions/common/actions';
1018
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
19+
import { Registry } from 'vs/platform/registry/common/platform';
20+
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
21+
import { activeContrastBorder, focusBorder } from 'vs/platform/theme/common/colorRegistry';
22+
import { ICssStyleCollector, ITheme, IThemeService, registerThemingParticipant } from 'vs/platform/theme/common/themeService';
23+
import { ActivityAction, ActivityActionItem, ICompositeBar, ICompositeBarColors, ToggleCompositePinnedAction } from 'vs/workbench/browser/parts/compositeBarActions';
1124
import { ViewletDescriptor } from 'vs/workbench/browser/viewlet';
25+
import { Extensions as ActionExtensions, IWorkbenchActionRegistry } from 'vs/workbench/common/actions';
1226
import { IActivity, IGlobalActivity } from 'vs/workbench/common/activity';
13-
import { dispose } from 'vs/base/common/lifecycle';
14-
import { IViewletService, } from 'vs/workbench/services/viewlet/browser/viewlet';
15-
import { IPartService, Parts } from 'vs/workbench/services/part/common/partService';
16-
import { IThemeService, ITheme, registerThemingParticipant, ICssStyleCollector } from 'vs/platform/theme/common/themeService';
17-
import { activeContrastBorder, focusBorder } from 'vs/platform/theme/common/colorRegistry';
18-
import { StandardMouseEvent } from 'vs/base/browser/mouseEvent';
19-
import { KeyCode } from 'vs/base/common/keyCodes';
20-
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
21-
import { ActivityAction, ActivityActionItem, ICompositeBarColors, ToggleCompositePinnedAction, ICompositeBar } from 'vs/workbench/browser/parts/compositeBarActions';
22-
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
23-
import { URI } from 'vs/base/common/uri';
2427
import { ACTIVITY_BAR_FOREGROUND } from 'vs/workbench/common/theme';
28+
import { IActivityService } from 'vs/workbench/services/activity/common/activity';
29+
import { IPartService, Parts } from 'vs/workbench/services/part/common/partService';
30+
import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet';
2531

2632
export class ViewletActivityAction extends ActivityAction {
2733

@@ -188,6 +194,77 @@ export class PlaceHolderToggleCompositePinnedAction extends ToggleCompositePinne
188194
}
189195
}
190196

197+
class SwitchSidebarViewAction extends Action {
198+
199+
constructor(
200+
id: string,
201+
name: string,
202+
@IViewletService private viewletService: IViewletService,
203+
@IActivityService private activityService: IActivityService
204+
) {
205+
super(id, name);
206+
}
207+
208+
run(offset: number): TPromise<any> {
209+
const pinnedViewletIds = this.activityService.getPinnedViewletIds();
210+
211+
const activeViewlet = this.viewletService.getActiveViewlet();
212+
if (!activeViewlet) {
213+
return TPromise.as(null);
214+
}
215+
let targetViewletId: string;
216+
for (let i = 0; i < pinnedViewletIds.length; i++) {
217+
if (pinnedViewletIds[i] === activeViewlet.getId()) {
218+
targetViewletId = pinnedViewletIds[(i + pinnedViewletIds.length + offset) % pinnedViewletIds.length];
219+
break;
220+
}
221+
}
222+
return this.viewletService.openViewlet(targetViewletId, true);
223+
}
224+
}
225+
226+
export class PreviousSidebarViewAction extends SwitchSidebarViewAction {
227+
228+
static readonly ID = 'workbench.action.previousSidebarView';
229+
static LABEL = nls.localize('previousSidebarView', 'Previous Sidebar View');
230+
231+
constructor(
232+
id: string,
233+
name: string,
234+
@IViewletService viewletService: IViewletService,
235+
@IActivityService activityService: IActivityService
236+
) {
237+
super(id, name, viewletService, activityService);
238+
}
239+
240+
run(): TPromise<any> {
241+
return super.run(-1);
242+
}
243+
}
244+
245+
export class NextSidebarViewAction extends SwitchSidebarViewAction {
246+
247+
static readonly ID = 'workbench.action.nextSidebarView';
248+
static LABEL = nls.localize('nextSidebarView', 'Next Sidebar View');
249+
250+
constructor(
251+
id: string,
252+
name: string,
253+
@IViewletService viewletService: IViewletService,
254+
@IActivityService activityService: IActivityService
255+
) {
256+
super(id, name, viewletService, activityService);
257+
}
258+
259+
run(): TPromise<any> {
260+
return super.run(1);
261+
}
262+
}
263+
264+
const registry = Registry.as<IWorkbenchActionRegistry>(ActionExtensions.WorkbenchActions);
265+
registry.registerWorkbenchAction(new SyncActionDescriptor(PreviousSidebarViewAction, PreviousSidebarViewAction.ID, PreviousSidebarViewAction.LABEL), 'View: Open Previous Sidebar View', nls.localize('view', "View"));
266+
registry.registerWorkbenchAction(new SyncActionDescriptor(NextSidebarViewAction, NextSidebarViewAction.ID, NextSidebarViewAction.LABEL), 'View: Open Next Sidebar View', nls.localize('view', "View"));
267+
191268
registerThemingParticipant((theme: ITheme, collector: ICssStyleCollector) => {
192269

193270
const activeForegroundColor = theme.getColor(ACTIVITY_BAR_FOREGROUND);

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

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -304,8 +304,12 @@ export class ActivitybarPart extends Part {
304304
}
305305
}
306306

307-
getPinned(): string[] {
308-
return this.viewletService.getViewlets().map(v => v.id).filter(id => this.compositeBar.isPinned(id));
307+
getPinnedViewletIds(): string[] {
308+
const pinnedCompositeIds = this.compositeBar.getPinnedComposites().map(v => v.id);
309+
return this.viewletService.getViewlets()
310+
.filter(v => this.compositeBar.isPinned(v.id))
311+
.sort((v1, v2) => pinnedCompositeIds.indexOf(v1.id) - pinnedCompositeIds.indexOf(v2.id))
312+
.map(v => v.id);
309313
}
310314

311315
layout(dimension: Dimension): Dimension[] {

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,10 @@ export class CompositeBar extends Widget implements ICompositeBar {
7070
return this.model.items;
7171
}
7272

73+
getPinnedComposites(): ICompositeBarItem[] {
74+
return this.model.pinnedItems;
75+
}
76+
7377
create(parent: HTMLElement): HTMLElement {
7478
const actionBarDiv = parent.appendChild($('.composite-bar'));
7579
this.compositeSwitcherBar = this._register(new ActionBar(actionBarDiv, {
@@ -458,6 +462,10 @@ class CompositeBarModel {
458462
return this.items.filter(item => item.visible);
459463
}
460464

465+
get pinnedItems(): ICompositeBarItem[] {
466+
return this.items.filter(item => item.visible && item.pinned);
467+
}
468+
461469
private createCompositeBarItem(id: string, name: string, order: number, pinned: boolean, visible: boolean): ICompositeBarItem {
462470
const options = this.options;
463471
return {

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

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,13 +179,78 @@ export class PanelActivityAction extends ActivityAction {
179179
}
180180
}
181181

182+
export class SwitchPanelViewAction extends Action {
183+
184+
constructor(
185+
id: string,
186+
name: string,
187+
@IPanelService private panelService: IPanelService
188+
) {
189+
super(id, name);
190+
}
191+
192+
run(offset: number): TPromise<any> {
193+
const pinnedPanels = this.panelService.getPinnedPanels();
194+
const activePanel = this.panelService.getActivePanel();
195+
if (!activePanel) {
196+
return TPromise.as(null);
197+
}
198+
let targetPanelId: string;
199+
for (let i = 0; i < pinnedPanels.length; i++) {
200+
if (pinnedPanels[i].id === activePanel.getId()) {
201+
targetPanelId = pinnedPanels[(i + pinnedPanels.length + offset) % pinnedPanels.length].id;
202+
break;
203+
}
204+
}
205+
return this.panelService.openPanel(targetPanelId, true);
206+
}
207+
}
208+
209+
export class PreviousPanelViewAction extends SwitchPanelViewAction {
210+
211+
static readonly ID = 'workbench.action.previousPanelView';
212+
static LABEL = nls.localize('previousPanelView', 'Previous Panel View');
213+
214+
constructor(
215+
id: string,
216+
name: string,
217+
@IPanelService panelService: IPanelService
218+
) {
219+
super(id, name, panelService);
220+
}
221+
222+
run(): TPromise<any> {
223+
return super.run(-1);
224+
}
225+
}
226+
227+
export class NextPanelViewAction extends SwitchPanelViewAction {
228+
229+
static readonly ID = 'workbench.action.nextPanelView';
230+
static LABEL = nls.localize('nextPanelView', 'Next Panel View');
231+
232+
constructor(
233+
id: string,
234+
name: string,
235+
@IPanelService panelService: IPanelService
236+
) {
237+
super(id, name, panelService);
238+
}
239+
240+
public run(): TPromise<any> {
241+
return super.run(1);
242+
}
243+
}
244+
182245
const actionRegistry = Registry.as<IWorkbenchActionRegistry>(WorkbenchExtensions.WorkbenchActions);
183246
actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(TogglePanelAction, TogglePanelAction.ID, TogglePanelAction.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.KEY_J }), 'View: Toggle Panel', nls.localize('view', "View"));
184247
actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(FocusPanelAction, FocusPanelAction.ID, FocusPanelAction.LABEL), 'View: Focus into Panel', nls.localize('view', "View"));
185248
actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ToggleMaximizedPanelAction, ToggleMaximizedPanelAction.ID, ToggleMaximizedPanelAction.LABEL), 'View: Toggle Maximized Panel', nls.localize('view', "View"));
186249
actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ClosePanelAction, ClosePanelAction.ID, ClosePanelAction.LABEL), 'View: Close Panel', nls.localize('view', "View"));
187250
actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(TogglePanelPositionAction, TogglePanelPositionAction.ID, TogglePanelPositionAction.LABEL), 'View: Toggle Panel Position', nls.localize('view', "View"));
188251
actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ToggleMaximizedPanelAction, ToggleMaximizedPanelAction.ID, undefined), 'View: Toggle Panel Position', nls.localize('view', "View"));
252+
actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(PreviousPanelViewAction, PreviousPanelViewAction.ID, PreviousPanelViewAction.LABEL), 'View: Open Previous Panel View', nls.localize('view', "View"));
253+
actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(NextPanelViewAction, NextPanelViewAction.ID, NextPanelViewAction.LABEL), 'View: Open Next Panel View', nls.localize('view', "View"));
189254

190255
MenuRegistry.appendMenuItem(MenuId.MenubarAppearanceMenu, {
191256
group: '2_workbench_layout',

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,13 @@ export class PanelPart extends CompositePart<Panel> implements IPanelService {
198198
.sort((v1, v2) => v1.order - v2.order);
199199
}
200200

201+
getPinnedPanels(): PanelDescriptor[] {
202+
const pinnedCompositeIds = this.compositeBar.getPinnedComposites().map(c => c.id);
203+
return this.getPanels()
204+
.filter(p => pinnedCompositeIds.indexOf(p.id) !== -1)
205+
.sort((p1, p2) => pinnedCompositeIds.indexOf(p1.id) - pinnedCompositeIds.indexOf(p2.id));
206+
}
207+
201208
setPanelEnablement(id: string, enabled: boolean): void {
202209
const descriptor = Registry.as<PanelRegistry>(PanelExtensions.Panels).getPanels().filter(p => p.id === id).pop();
203210
if (descriptor && descriptor.enabled !== enabled) {

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -767,7 +767,7 @@ export class Workbench extends Disposable implements IPartService {
767767

768768
return {
769769
customKeybindingsCount: this.keybindingService.customKeybindingsCount(),
770-
pinnedViewlets: this.activitybarPart.getPinned(),
770+
pinnedViewlets: this.activitybarPart.getPinnedViewletIds(),
771771
restoredViewlet: viewletIdToRestore,
772772
restoredEditorsCount: this.editorService.visibleEditors.length
773773
};

src/vs/workbench/services/activity/browser/activityService.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,4 +26,9 @@ export class ActivityService implements IActivityService {
2626

2727
return this.activitybarPart.showActivity(compositeOrActionId, badge, clazz, priority);
2828
}
29+
30+
getPinnedViewletIds(): string[] {
31+
return this.activitybarPart.getPinnedViewletIds();
32+
}
33+
2934
}

src/vs/workbench/services/activity/common/activity.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,4 +65,9 @@ export interface IActivityService {
6565
* Show activity in the panel for the given panel or in the activitybar for the given viewlet or global action.
6666
*/
6767
showActivity(compositeOrActionId: string, badge: IBadge, clazz?: string, priority?: number): IDisposable;
68+
69+
/**
70+
* Returns id of pinned viewlets following the visual order
71+
*/
72+
getPinnedViewletIds(): string[];
6873
}

src/vs/workbench/services/panel/common/panelService.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,15 @@ export interface IPanelService {
3434
getActivePanel(): IPanel;
3535

3636
/**
37-
* Returns all enabled panels
37+
* * Returns all built-in panels following the default order (Problems - Output - Debug Console - Terminal)
3838
*/
3939
getPanels(): IPanelIdentifier[];
4040

41+
/**
42+
* Returns pinned panels following the visual order
43+
*/
44+
getPinnedPanels(): IPanelIdentifier[];
45+
4146
/**
4247
* Enables or disables a panel. Disabled panels are completly hidden from UI.
4348
* By default all panels are enabled.

src/vs/workbench/services/progress/test/progressService.test.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,10 @@ class TestPanelService implements IPanelService {
7777
return [];
7878
}
7979

80+
public getPinnedPanels(): any[] {
81+
return [];
82+
}
83+
8084
public getActivePanel(): IViewlet {
8185
return activeViewlet;
8286
}

0 commit comments

Comments
 (0)