提交 943b7823 编写于 作者: B Benjamin Pasero

paper cut - offer a menu to control visibility of status bar entries

上级 bd39f3d7
...@@ -11,7 +11,13 @@ import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions'; ...@@ -11,7 +11,13 @@ import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
export const IStatusbarService = createDecorator<IStatusbarService>('statusbarService'); export const IStatusbarService = createDecorator<IStatusbarService>('statusbarService');
export const enum StatusbarAlignment { export const enum StatusbarAlignment {
LEFT, RIGHT LEFT,
RIGHT
}
export interface IStatusbarEntryCategory {
id: string;
label: string;
} }
/** /**
...@@ -19,6 +25,11 @@ export const enum StatusbarAlignment { ...@@ -19,6 +25,11 @@ export const enum StatusbarAlignment {
*/ */
export interface IStatusbarEntry { export interface IStatusbarEntry {
/**
* The category of the entry is needed to allow users to hide entries via settings.
*/
readonly category: IStatusbarEntryCategory;
/** /**
* The text to show for the entry. You can embed icons in the text by leveraging the syntax: * The text to show for the entry. You can embed icons in the text by leveraging the syntax:
* *
......
...@@ -3,12 +3,13 @@ ...@@ -3,12 +3,13 @@
* Licensed under the MIT License. See License.txt in the project root for license information. * Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/ *--------------------------------------------------------------------------------------------*/
import { IStatusbarService, StatusbarAlignment as MainThreadStatusBarAlignment, IStatusbarEntryAccessor } from 'vs/platform/statusbar/common/statusbar'; import { IStatusbarService, StatusbarAlignment as MainThreadStatusBarAlignment, IStatusbarEntryAccessor, IStatusbarEntry } from 'vs/platform/statusbar/common/statusbar';
import { MainThreadStatusBarShape, MainContext, IExtHostContext } from '../common/extHost.protocol'; import { MainThreadStatusBarShape, MainContext, IExtHostContext } from '../common/extHost.protocol';
import { ThemeColor } from 'vs/platform/theme/common/themeService'; import { ThemeColor } from 'vs/platform/theme/common/themeService';
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers'; import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions'; import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
import { dispose } from 'vs/base/common/lifecycle'; import { dispose } from 'vs/base/common/lifecycle';
import { localize } from 'vs/nls';
@extHostNamedCustomer(MainContext.MainThreadStatusBar) @extHostNamedCustomer(MainContext.MainThreadStatusBar)
export class MainThreadStatusBar implements MainThreadStatusBarShape { export class MainThreadStatusBar implements MainThreadStatusBarShape {
...@@ -25,8 +26,18 @@ export class MainThreadStatusBar implements MainThreadStatusBarShape { ...@@ -25,8 +26,18 @@ export class MainThreadStatusBar implements MainThreadStatusBarShape {
this.entries.clear(); this.entries.clear();
} }
$setEntry(id: number, extensionId: ExtensionIdentifier, text: string, tooltip: string, command: string, color: string | ThemeColor, alignment: MainThreadStatusBarAlignment, priority: number): void { $setEntry(id: number, extension: IExtensionDescription, text: string, tooltip: string, command: string, color: string | ThemeColor, alignment: MainThreadStatusBarAlignment, priority: number): void {
const entry = { text, tooltip, command, color, extensionId }; const entry: IStatusbarEntry = {
category: {
id: extension.identifier.value,
label: localize('extensionLabel', "{0} (Extension)", extension.displayName || extension.name)
},
text,
tooltip,
command,
color,
extensionId: extension.identifier
};
// Reset existing entry if alignment or priority changed // Reset existing entry if alignment or priority changed
let existingEntry = this.entries.get(id); let existingEntry = this.entries.get(id);
......
...@@ -495,7 +495,7 @@ export interface MainThreadQuickOpenShape extends IDisposable { ...@@ -495,7 +495,7 @@ export interface MainThreadQuickOpenShape extends IDisposable {
} }
export interface MainThreadStatusBarShape extends IDisposable { export interface MainThreadStatusBarShape extends IDisposable {
$setEntry(id: number, extensionId: ExtensionIdentifier | undefined, text: string, tooltip: string, command: string, color: string | ThemeColor, alignment: statusbar.StatusbarAlignment, priority: number | undefined): void; $setEntry(id: number, extension: IExtensionDescription | undefined, text: string, tooltip: string, command: string, color: string | ThemeColor, alignment: statusbar.StatusbarAlignment, priority: number | undefined): void;
$dispose(id: number): void; $dispose(id: number): void;
} }
......
...@@ -7,7 +7,7 @@ import { StatusbarAlignment as MainThreadStatusBarAlignment } from 'vs/platform/ ...@@ -7,7 +7,7 @@ import { StatusbarAlignment as MainThreadStatusBarAlignment } from 'vs/platform/
import { StatusBarAlignment as ExtHostStatusBarAlignment, Disposable, ThemeColor } from './extHostTypes'; import { StatusBarAlignment as ExtHostStatusBarAlignment, Disposable, ThemeColor } from './extHostTypes';
import { StatusBarItem, StatusBarAlignment } from 'vscode'; import { StatusBarItem, StatusBarAlignment } from 'vscode';
import { MainContext, MainThreadStatusBarShape, IMainContext } from './extHost.protocol'; import { MainContext, MainThreadStatusBarShape, IMainContext } from './extHost.protocol';
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions'; import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
export class ExtHostStatusBarEntry implements StatusBarItem { export class ExtHostStatusBarEntry implements StatusBarItem {
private static ID_GEN = 0; private static ID_GEN = 0;
...@@ -26,14 +26,14 @@ export class ExtHostStatusBarEntry implements StatusBarItem { ...@@ -26,14 +26,14 @@ export class ExtHostStatusBarEntry implements StatusBarItem {
private _timeoutHandle: any; private _timeoutHandle: any;
private _proxy: MainThreadStatusBarShape; private _proxy: MainThreadStatusBarShape;
private _extensionId?: ExtensionIdentifier; private _extension?: IExtensionDescription;
constructor(proxy: MainThreadStatusBarShape, extensionId: ExtensionIdentifier | undefined, alignment: ExtHostStatusBarAlignment = ExtHostStatusBarAlignment.Left, priority?: number) { constructor(proxy: MainThreadStatusBarShape, extension: IExtensionDescription | undefined, alignment: ExtHostStatusBarAlignment = ExtHostStatusBarAlignment.Left, priority?: number) {
this._id = ExtHostStatusBarEntry.ID_GEN++; this._id = ExtHostStatusBarEntry.ID_GEN++;
this._proxy = proxy; this._proxy = proxy;
this._alignment = alignment; this._alignment = alignment;
this._priority = priority; this._priority = priority;
this._extensionId = extensionId; this._extension = extension;
} }
public get id(): number { public get id(): number {
...@@ -107,7 +107,7 @@ export class ExtHostStatusBarEntry implements StatusBarItem { ...@@ -107,7 +107,7 @@ export class ExtHostStatusBarEntry implements StatusBarItem {
this._timeoutHandle = undefined; this._timeoutHandle = undefined;
// Set to status bar // Set to status bar
this._proxy.$setEntry(this.id, this._extensionId, this.text, this.tooltip, this.command, this.color, this._proxy.$setEntry(this.id, this._extension, this.text, this.tooltip, this.command, this.color,
this._alignment === ExtHostStatusBarAlignment.Left ? MainThreadStatusBarAlignment.LEFT : MainThreadStatusBarAlignment.RIGHT, this._alignment === ExtHostStatusBarAlignment.Left ? MainThreadStatusBarAlignment.LEFT : MainThreadStatusBarAlignment.RIGHT,
this._priority); this._priority);
}, 0); }, 0);
...@@ -167,8 +167,8 @@ export class ExtHostStatusBar { ...@@ -167,8 +167,8 @@ export class ExtHostStatusBar {
this._statusMessage = new StatusBarMessage(this); this._statusMessage = new StatusBarMessage(this);
} }
createStatusBarEntry(extensionId: ExtensionIdentifier | undefined, alignment?: ExtHostStatusBarAlignment, priority?: number): StatusBarItem { createStatusBarEntry(extension: IExtensionDescription | undefined, alignment?: ExtHostStatusBarAlignment, priority?: number): StatusBarItem {
return new ExtHostStatusBarEntry(this._proxy, extensionId, alignment, priority); return new ExtHostStatusBarEntry(this._proxy, extension, alignment, priority);
} }
setStatusBarMessage(text: string, timeoutOrThenable?: number | Thenable<any>): Disposable { setStatusBarMessage(text: string, timeoutOrThenable?: number | Thenable<any>): Disposable {
......
...@@ -466,7 +466,7 @@ export function createApiFactory( ...@@ -466,7 +466,7 @@ export function createApiFactory(
return extHostDialogs.showSaveDialog(options); return extHostDialogs.showSaveDialog(options);
}, },
createStatusBarItem(position?: vscode.StatusBarAlignment, priority?: number): vscode.StatusBarItem { createStatusBarItem(position?: vscode.StatusBarAlignment, priority?: number): vscode.StatusBarItem {
return extHostStatusBar.createStatusBarEntry(extension.identifier, <number>position, priority); return extHostStatusBar.createStatusBarEntry(extension, <number>position, priority);
}, },
setStatusBarMessage(text: string, timeoutOrThenable?: number | Thenable<any>): vscode.Disposable { setStatusBarMessage(text: string, timeoutOrThenable?: number | Thenable<any>): vscode.Disposable {
return extHostStatusBar.setStatusBarMessage(text, timeoutOrThenable); return extHostStatusBar.setStatusBarMessage(text, timeoutOrThenable);
......
...@@ -221,10 +221,20 @@ registerEditorContribution(OpenWorkspaceButtonContribution); ...@@ -221,10 +221,20 @@ registerEditorContribution(OpenWorkspaceButtonContribution);
// Register Editor Status // Register Editor Status
const statusBar = Registry.as<IStatusbarRegistry>(StatusExtensions.Statusbar); const statusBar = Registry.as<IStatusbarRegistry>(StatusExtensions.Statusbar);
statusBar.registerStatusbarItem(new StatusbarItemDescriptor(EditorStatus, StatusbarAlignment.RIGHT, 100 /* towards the left of the right hand side */)); statusBar.registerStatusbarItem(new StatusbarItemDescriptor(
EditorStatus,
{ id: 'status.editor', label: nls.localize('status.editor', "Editor Status") },
StatusbarAlignment.RIGHT,
100 /* towards the left of the right hand side */
));
// Register Zoom Status // Register Zoom Status
statusBar.registerStatusbarItem(new StatusbarItemDescriptor(ZoomStatusbarItem, StatusbarAlignment.RIGHT, 101 /* to the left of editor status (100) */)); statusBar.registerStatusbarItem(new StatusbarItemDescriptor(
ZoomStatusbarItem,
{ id: 'status.imageZoom', label: nls.localize('status.imageZoom', "Image Zoom") },
StatusbarAlignment.RIGHT,
101 /* to the left of editor status (100) */)
);
// Register Status Actions // Register Status Actions
const registry = Registry.as<IWorkbenchActionRegistry>(ActionExtensions.WorkbenchActions); const registry = Registry.as<IWorkbenchActionRegistry>(ActionExtensions.WorkbenchActions);
......
...@@ -58,6 +58,7 @@ export class NotificationsStatus extends Disposable { ...@@ -58,6 +58,7 @@ export class NotificationsStatus extends Disposable {
private updateNotificationsCenterStatusItem(): void { private updateNotificationsCenterStatusItem(): void {
const statusProperties: IStatusbarEntry = { const statusProperties: IStatusbarEntry = {
category: { id: 'status.notifications', label: localize('status.notifications', "Notifictions") },
text: this.currentNotifications.size === 0 ? '$(bell)' : `$(bell) ${this.currentNotifications.size}`, text: this.currentNotifications.size === 0 ? '$(bell)' : `$(bell) ${this.currentNotifications.size}`,
command: this.isNotificationsCenterVisible ? HIDE_NOTIFICATIONS_CENTER : SHOW_NOTIFICATIONS_CENTER, command: this.isNotificationsCenterVisible ? HIDE_NOTIFICATIONS_CENTER : SHOW_NOTIFICATIONS_CENTER,
tooltip: this.getTooltip(), tooltip: this.getTooltip(),
...@@ -137,7 +138,10 @@ export class NotificationsStatus extends Disposable { ...@@ -137,7 +138,10 @@ export class NotificationsStatus extends Disposable {
// Create new // Create new
let statusMessageEntry: IStatusbarEntryAccessor; let statusMessageEntry: IStatusbarEntryAccessor;
let showHandle: any = setTimeout(() => { let showHandle: any = setTimeout(() => {
statusMessageEntry = this.statusbarService.addEntry({ text: message }, StatusbarAlignment.LEFT, -Number.MAX_VALUE /* far right on left hand side */); statusMessageEntry = this.statusbarService.addEntry({
category: { id: 'status.message', label: localize('status.message', "Status Message") },
text: message
}, StatusbarAlignment.LEFT, -Number.MAX_VALUE /* far right on left hand side */);
showHandle = null; showHandle = null;
}, showAfter); }, showAfter);
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
import { Registry } from 'vs/platform/registry/common/platform'; import { Registry } from 'vs/platform/registry/common/platform';
import { IDisposable } from 'vs/base/common/lifecycle'; import { IDisposable } from 'vs/base/common/lifecycle';
import { StatusbarAlignment } from 'vs/platform/statusbar/common/statusbar'; import { StatusbarAlignment, IStatusbarEntryCategory } from 'vs/platform/statusbar/common/statusbar';
import { SyncDescriptor0, createSyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; import { SyncDescriptor0, createSyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
import { IConstructorSignature0 } from 'vs/platform/instantiation/common/instantiation'; import { IConstructorSignature0 } from 'vs/platform/instantiation/common/instantiation';
...@@ -14,11 +14,18 @@ export interface IStatusbarItem { ...@@ -14,11 +14,18 @@ export interface IStatusbarItem {
} }
export class StatusbarItemDescriptor { export class StatusbarItemDescriptor {
syncDescriptor: SyncDescriptor0<IStatusbarItem>; readonly syncDescriptor: SyncDescriptor0<IStatusbarItem>;
alignment: StatusbarAlignment; readonly category: IStatusbarEntryCategory;
priority: number; readonly alignment: StatusbarAlignment;
readonly priority: number;
constructor(ctor: IConstructorSignature0<IStatusbarItem>, alignment?: StatusbarAlignment, priority?: number) {
constructor(
ctor: IConstructorSignature0<IStatusbarItem>,
category: IStatusbarEntryCategory,
alignment?: StatusbarAlignment,
priority?: number
) {
this.category = category;
this.syncDescriptor = createSyncDescriptor(ctor); this.syncDescriptor = createSyncDescriptor(ctor);
this.alignment = alignment || StatusbarAlignment.LEFT; this.alignment = alignment || StatusbarAlignment.LEFT;
this.priority = priority || 0; this.priority = priority || 0;
...@@ -26,21 +33,16 @@ export class StatusbarItemDescriptor { ...@@ -26,21 +33,16 @@ export class StatusbarItemDescriptor {
} }
export interface IStatusbarRegistry { export interface IStatusbarRegistry {
readonly items: StatusbarItemDescriptor[];
registerStatusbarItem(descriptor: StatusbarItemDescriptor): void; registerStatusbarItem(descriptor: StatusbarItemDescriptor): void;
items: StatusbarItemDescriptor[];
} }
class StatusbarRegistry implements IStatusbarRegistry { class StatusbarRegistry implements IStatusbarRegistry {
private _items: StatusbarItemDescriptor[]; private readonly _items: StatusbarItemDescriptor[] = [];
get items(): StatusbarItemDescriptor[] { return this._items; }
constructor() {
this._items = [];
}
get items(): StatusbarItemDescriptor[] {
return this._items;
}
registerStatusbarItem(descriptor: StatusbarItemDescriptor): void { registerStatusbarItem(descriptor: StatusbarItemDescriptor): void {
this._items.push(descriptor); this._items.push(descriptor);
......
...@@ -15,7 +15,7 @@ import { Part } from 'vs/workbench/browser/part'; ...@@ -15,7 +15,7 @@ import { Part } from 'vs/workbench/browser/part';
import { IStatusbarRegistry, Extensions } from 'vs/workbench/browser/parts/statusbar/statusbar'; import { IStatusbarRegistry, Extensions } from 'vs/workbench/browser/parts/statusbar/statusbar';
import { IInstantiationService, ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation'; import { IInstantiationService, ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { StatusbarAlignment, IStatusbarService, IStatusbarEntry, IStatusbarEntryAccessor } from 'vs/platform/statusbar/common/statusbar'; import { StatusbarAlignment, IStatusbarService, IStatusbarEntry, IStatusbarEntryAccessor, IStatusbarEntryCategory } from 'vs/platform/statusbar/common/statusbar';
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
import { Action, IAction } from 'vs/base/common/actions'; import { Action, IAction } from 'vs/base/common/actions';
import { IThemeService, registerThemingParticipant, ITheme, ICssStyleCollector, ThemeColor } from 'vs/platform/theme/common/themeService'; import { IThemeService, registerThemingParticipant, ITheme, ICssStyleCollector, ThemeColor } from 'vs/platform/theme/common/themeService';
...@@ -24,23 +24,208 @@ import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/ ...@@ -24,23 +24,208 @@ import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/
import { contrastBorder } from 'vs/platform/theme/common/colorRegistry'; import { contrastBorder } from 'vs/platform/theme/common/colorRegistry';
import { isThemeColor } from 'vs/editor/common/editorCommon'; import { isThemeColor } from 'vs/editor/common/editorCommon';
import { Color } from 'vs/base/common/color'; import { Color } from 'vs/base/common/color';
import { addClass, EventHelper, createStyleSheet, addDisposableListener, addClasses, clearNode, removeClass, EventType } from 'vs/base/browser/dom'; import { addClass, EventHelper, createStyleSheet, addDisposableListener, addClasses, clearNode, removeClass, EventType, hide, show } from 'vs/base/browser/dom';
import { INotificationService } from 'vs/platform/notification/common/notification'; import { INotificationService } from 'vs/platform/notification/common/notification';
import { IStorageService } from 'vs/platform/storage/common/storage'; import { IStorageService, StorageScope, IWorkspaceStorageChangeEvent } from 'vs/platform/storage/common/storage';
import { Parts, IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService'; import { Parts, IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService';
import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
import { coalesce } from 'vs/base/common/arrays'; import { coalesce } from 'vs/base/common/arrays';
import { StandardMouseEvent } from 'vs/base/browser/mouseEvent'; import { StandardMouseEvent } from 'vs/base/browser/mouseEvent';
import { ToggleStatusbarVisibilityAction } from 'vs/workbench/browser/actions/layoutActions'; import { ToggleStatusbarVisibilityAction } from 'vs/workbench/browser/actions/layoutActions';
import { Separator } from 'vs/base/browser/ui/actionbar/actionbar';
import { Event, Emitter } from 'vs/base/common/event';
import { values } from 'vs/base/common/map';
interface IPendingStatusbarEntry {
entry: IStatusbarEntry;
alignment: StatusbarAlignment;
priority: number;
accessor?: IStatusbarEntryAccessor;
}
interface IStatusbarViewModelItem {
category: IStatusbarEntryCategory;
alignment: StatusbarAlignment;
priority: number;
}
class StatusbarViewModel extends Disposable {
private static readonly HIDDEN_CATEGORIES_KEY = 'workbench.statusbar.hidden';
private readonly _items: IStatusbarViewModelItem[] = [];
get items(): IStatusbarViewModelItem[] { return this._items; }
private readonly _onDidCategoryVisibilityChange: Emitter<IStatusbarEntryCategory> = this._register(new Emitter());
get onDidCategoryVisibilityChange(): Event<IStatusbarEntryCategory> { return this._onDidCategoryVisibilityChange.event; }
private hiddenCategories: Set<string>;
constructor(private storageService: IStorageService) {
super();
this.restoreState();
this.registerListeners();
}
private restoreState(): void {
const hiddenCategoriesRaw = this.storageService.get(StatusbarViewModel.HIDDEN_CATEGORIES_KEY, StorageScope.GLOBAL);
if (hiddenCategoriesRaw) {
try {
const hiddenCategoriesArray: string[] = JSON.parse(hiddenCategoriesRaw);
this.hiddenCategories = new Set(hiddenCategoriesArray);
} catch (error) {
// ignore parsing errors
}
}
if (!this.hiddenCategories) {
this.hiddenCategories = new Set<string>();
}
}
private registerListeners(): void {
this._register(this.storageService.onDidChangeStorage(e => this.onDidStorageChange(e)));
}
private onDidStorageChange(event: IWorkspaceStorageChangeEvent): void {
if (event.key === StatusbarViewModel.HIDDEN_CATEGORIES_KEY && event.scope === StorageScope.GLOBAL) {
// Keep current hidden categories
const currentHiddenCategories = this.hiddenCategories;
// Load latest state of hidden categories
this.restoreState();
const changedCategories = new Set<string>();
// Check for each category that is now visible
currentHiddenCategories.forEach(category => {
if (!this.hiddenCategories.has(category)) {
changedCategories.add(category);
}
});
// Check for each category that is now hidden
this.hiddenCategories.forEach(category => {
if (!currentHiddenCategories.has(category)) {
changedCategories.add(category);
}
});
// Notify listeners that visibility for categories that changed
this._items.forEach(item => {
if (changedCategories.has(item.category.id)) {
this._onDidCategoryVisibilityChange.fire(item.category);
changedCategories.delete(item.category.id);
}
});
}
}
add(item: IStatusbarViewModelItem): void {
this._items.push(item);
this.sort();
}
interface PendingEntry { entry: IStatusbarEntry; alignment: StatusbarAlignment; priority: number; accessor?: IStatusbarEntryAccessor; } remove(item: IStatusbarViewModelItem): void {
const index = this._items.indexOf(item);
if (index >= 0) {
this._items.splice(index, 1);
}
}
isHidden(category: IStatusbarEntryCategory): boolean {
return this.hiddenCategories.has(category.id);
}
hide(category: IStatusbarEntryCategory): void {
if (!this.hiddenCategories.has(category.id)) {
this.hiddenCategories.add(category.id);
this._onDidCategoryVisibilityChange.fire(category);
this.saveState();
}
}
show(category: IStatusbarEntryCategory): void {
if (this.hiddenCategories.has(category.id)) {
this.hiddenCategories.delete(category.id);
this._onDidCategoryVisibilityChange.fire(category);
this.saveState();
}
}
private saveState(): void {
if (this.hiddenCategories.size > 0) {
this.storageService.store(StatusbarViewModel.HIDDEN_CATEGORIES_KEY, JSON.stringify(values(this.hiddenCategories)), StorageScope.GLOBAL);
} else {
this.storageService.remove(StatusbarViewModel.HIDDEN_CATEGORIES_KEY, StorageScope.GLOBAL);
}
}
private sort(): void {
this._items.sort((itemA, itemB) => {
if (itemA.alignment === itemB.alignment) {
return itemB.priority - itemA.priority;
}
if (itemA.alignment === StatusbarAlignment.LEFT) {
return -1;
}
if (itemB.alignment === StatusbarAlignment.LEFT) {
return 1;
}
return 0;
});
}
}
class ToggleStatusCategoryVisibilityAction extends Action {
constructor(private category: IStatusbarEntryCategory, private model: StatusbarViewModel) {
super(category.id, category.label, undefined, true);
this.checked = !model.isHidden(category);
}
run(): Promise<any> {
if (this.model.isHidden(this.category)) {
this.model.show(this.category);
} else {
this.model.hide(this.category);
}
return Promise.resolve(true);
}
}
class HideStatusCategoryAction extends Action {
constructor(private category: IStatusbarEntryCategory, private model: StatusbarViewModel) {
super(category.id, nls.localize('hide', "Hide"), undefined, true);
}
run(): Promise<any> {
this.model.hide(this.category);
return Promise.resolve(true);
}
}
export class StatusbarPart extends Part implements IStatusbarService { export class StatusbarPart extends Part implements IStatusbarService {
_serviceBrand: ServiceIdentifier<IStatusbarService>; _serviceBrand: ServiceIdentifier<IStatusbarService>;
private static readonly PRIORITY_PROP = 'statusbar-entry-priority'; private static readonly PRIORITY_PROP = 'statusbar-item-priority';
private static readonly ALIGNMENT_PROP = 'statusbar-entry-alignment'; private static readonly ALIGNMENT_PROP = 'statusbar-item-alignment';
private static readonly CATEGORY_PROP = 'statusbar-item-category';
//#region IView //#region IView
...@@ -53,9 +238,9 @@ export class StatusbarPart extends Part implements IStatusbarService { ...@@ -53,9 +238,9 @@ export class StatusbarPart extends Part implements IStatusbarService {
private styleElement: HTMLStyleElement; private styleElement: HTMLStyleElement;
private pendingEntries: PendingEntry[] = []; private pendingEntries: IPendingStatusbarEntry[] = [];
private hideStatusBarAction: ToggleStatusbarVisibilityAction; private readonly viewModel: StatusbarViewModel;
constructor( constructor(
@IInstantiationService private readonly instantiationService: IInstantiationService, @IInstantiationService private readonly instantiationService: IInstantiationService,
...@@ -67,13 +252,27 @@ export class StatusbarPart extends Part implements IStatusbarService { ...@@ -67,13 +252,27 @@ export class StatusbarPart extends Part implements IStatusbarService {
) { ) {
super(Parts.STATUSBAR_PART, { hasTitle: false }, themeService, storageService, layoutService); super(Parts.STATUSBAR_PART, { hasTitle: false }, themeService, storageService, layoutService);
this.hideStatusBarAction = this._register(this.instantiationService.createInstance(ToggleStatusbarVisibilityAction, ToggleStatusbarVisibilityAction.ID, nls.localize('hideStatusBar', "Hide Status Bar"))); this.viewModel = this._register(new StatusbarViewModel(storageService));
this.registerListeners(); this.registerListeners();
} }
private registerListeners(): void { private registerListeners(): void {
this._register(this.contextService.onDidChangeWorkbenchState(() => this.updateStyles())); this._register(this.contextService.onDidChangeWorkbenchState(() => this.updateStyles()));
this._register(this.viewModel.onDidCategoryVisibilityChange(category => this.onDidCategoryVisibilityChange(category)));
}
private onDidCategoryVisibilityChange(category: IStatusbarEntryCategory): void {
const isHidden = this.viewModel.isHidden(category);
const items = this.getEntries(category);
items.forEach(item => {
if (isHidden) {
hide(item);
} else {
show(item);
}
});
} }
addEntry(entry: IStatusbarEntry, alignment: StatusbarAlignment, priority: number = 0): IStatusbarEntryAccessor { addEntry(entry: IStatusbarEntry, alignment: StatusbarAlignment, priority: number = 0): IStatusbarEntryAccessor {
...@@ -81,9 +280,15 @@ export class StatusbarPart extends Part implements IStatusbarService { ...@@ -81,9 +280,15 @@ export class StatusbarPart extends Part implements IStatusbarService {
// As long as we have not been created into a container yet, record all entries // As long as we have not been created into a container yet, record all entries
// that are pending so that they can get created at a later point // that are pending so that they can get created at a later point
if (!this.element) { if (!this.element) {
const pendingEntry: PendingEntry = { return this.doAddPendingEntry(entry, alignment, priority);
entry, alignment, priority }
};
// Otherwise add to view
return this.doAddEntry(entry, alignment, priority);
}
private doAddPendingEntry(entry: IStatusbarEntry, alignment: StatusbarAlignment, priority: number): IStatusbarEntryAccessor {
const pendingEntry: IPendingStatusbarEntry = { entry, alignment, priority };
this.pendingEntries.push(pendingEntry); this.pendingEntries.push(pendingEntry);
const accessor: IStatusbarEntryAccessor = { const accessor: IStatusbarEntryAccessor = {
...@@ -94,6 +299,7 @@ export class StatusbarPart extends Part implements IStatusbarService { ...@@ -94,6 +299,7 @@ export class StatusbarPart extends Part implements IStatusbarService {
pendingEntry.entry = entry; pendingEntry.entry = entry;
} }
}, },
dispose: () => { dispose: () => {
if (pendingEntry.accessor) { if (pendingEntry.accessor) {
pendingEntry.accessor.dispose(); pendingEntry.accessor.dispose();
...@@ -102,12 +308,19 @@ export class StatusbarPart extends Part implements IStatusbarService { ...@@ -102,12 +308,19 @@ export class StatusbarPart extends Part implements IStatusbarService {
} }
} }
}; };
return accessor; return accessor;
} }
private doAddEntry(entry: IStatusbarEntry, alignment: StatusbarAlignment, priority: number): IStatusbarEntryAccessor {
// Add to view model
const viewModelItem: IStatusbarViewModelItem = { category: entry.category, alignment, priority };
this.viewModel.add(viewModelItem);
// Render entry in status bar // Render entry in status bar
const el = this.doCreateStatusItem(alignment, priority, ...coalesce(['statusbar-entry', entry.showBeak ? 'has-beak' : undefined])); const itemContainer = this.doCreateStatusItem(entry.category, alignment, priority, ...coalesce(['statusbar-entry', entry.showBeak ? 'has-beak' : undefined]));
const item = this.instantiationService.createInstance(StatusBarEntryItem, el, entry); const item = this.instantiationService.createInstance(StatusbarEntryItem, itemContainer, entry);
// Insert according to priority // Insert according to priority
const container = this.element; const container = this.element;
...@@ -119,14 +332,14 @@ export class StatusbarPart extends Part implements IStatusbarService { ...@@ -119,14 +332,14 @@ export class StatusbarPart extends Part implements IStatusbarService {
alignment === StatusbarAlignment.LEFT && nPriority < priority || alignment === StatusbarAlignment.LEFT && nPriority < priority ||
alignment === StatusbarAlignment.RIGHT && nPriority > priority alignment === StatusbarAlignment.RIGHT && nPriority > priority
) { ) {
container.insertBefore(el, neighbour); container.insertBefore(itemContainer, neighbour);
inserted = true; inserted = true;
break; break;
} }
} }
if (!inserted) { if (!inserted) {
container.appendChild(el); container.appendChild(itemContainer);
} }
return { return {
...@@ -134,32 +347,44 @@ export class StatusbarPart extends Part implements IStatusbarService { ...@@ -134,32 +347,44 @@ export class StatusbarPart extends Part implements IStatusbarService {
// Update beak // Update beak
if (entry.showBeak) { if (entry.showBeak) {
addClass(el, 'has-beak'); addClass(itemContainer, 'has-beak');
} else { } else {
removeClass(el, 'has-beak'); removeClass(itemContainer, 'has-beak');
} }
// Update entry // Update entry
item.update(entry); item.update(entry);
}, },
dispose: () => { dispose: () => {
el.remove(); this.viewModel.remove(viewModelItem);
itemContainer.remove();
dispose(item); dispose(item);
} }
}; };
} }
private getEntries(alignment: StatusbarAlignment): HTMLElement[] { private getEntries(scope: StatusbarAlignment | IStatusbarEntryCategory): HTMLElement[] {
const entries: HTMLElement[] = []; const entries: HTMLElement[] = [];
const container = this.element; const container = this.element;
const children = container.children; const children = container.children;
for (let i = 0; i < children.length; i++) { for (let i = 0; i < children.length; i++) {
const childElement = <HTMLElement>children.item(i); const childElement = <HTMLElement>children.item(i);
if (Number(childElement.getAttribute(StatusbarPart.ALIGNMENT_PROP)) === alignment) {
// By alignment
if (typeof scope === 'number') {
if (Number(childElement.getAttribute(StatusbarPart.ALIGNMENT_PROP)) === scope) {
entries.push(childElement);
}
}
// By category
else {
if (childElement.getAttribute(StatusbarPart.CATEGORY_PROP) === scope.id) {
entries.push(childElement); entries.push(childElement);
} }
} }
}
return entries; return entries;
} }
...@@ -170,31 +395,48 @@ export class StatusbarPart extends Part implements IStatusbarService { ...@@ -170,31 +395,48 @@ export class StatusbarPart extends Part implements IStatusbarService {
// Context menu support // Context menu support
this._register(addDisposableListener(parent, EventType.CONTEXT_MENU, e => this.showContextMenu(e))); this._register(addDisposableListener(parent, EventType.CONTEXT_MENU, e => this.showContextMenu(e)));
// Fill in initial items that were contributed from the registry // Initial status bar entries
this.createInitialStatusEntries();
return this.element;
}
private createInitialStatusEntries(): void {
const registry = Registry.as<IStatusbarRegistry>(Extensions.Statusbar); const registry = Registry.as<IStatusbarRegistry>(Extensions.Statusbar);
const descriptors = registry.items.slice().sort((a, b) => { const descriptors = registry.items.slice().sort((itemA, itemB) => {
if (a.alignment === b.alignment) { if (itemA.alignment === itemB.alignment) {
if (a.alignment === StatusbarAlignment.LEFT) { if (itemA.alignment === StatusbarAlignment.LEFT) {
return b.priority - a.priority; return itemB.priority - itemA.priority;
} else { }
return a.priority - b.priority;
return itemA.priority - itemB.priority;
} }
} else if (a.alignment === StatusbarAlignment.LEFT) {
if (itemA.alignment === StatusbarAlignment.LEFT) {
return 1; return 1;
} else if (a.alignment === StatusbarAlignment.RIGHT) { }
if (itemA.alignment === StatusbarAlignment.RIGHT) {
return -1; return -1;
} else {
return 0;
} }
return 0;
}); });
for (const descriptor of descriptors) { // Fill in initial items that were contributed from the registry
const item = this.instantiationService.createInstance(descriptor.syncDescriptor); for (const { category, alignment, priority, syncDescriptor } of descriptors) {
const el = this.doCreateStatusItem(descriptor.alignment, descriptor.priority);
// Add to view model
const viewModelItem: IStatusbarViewModelItem = { category, alignment, priority };
this.viewModel.add(viewModelItem);
// Render
const item = this.instantiationService.createInstance(syncDescriptor);
const itemContainer = this.doCreateStatusItem(category, alignment, priority);
this._register(item.render(el)); this._register(item.render(itemContainer));
this.element.appendChild(el); this.element.appendChild(itemContainer);
} }
// Fill in pending entries if any // Fill in pending entries if any
...@@ -204,39 +446,57 @@ export class StatusbarPart extends Part implements IStatusbarService { ...@@ -204,39 +446,57 @@ export class StatusbarPart extends Part implements IStatusbarService {
entry.accessor = this.addEntry(entry.entry, entry.alignment, entry.priority); entry.accessor = this.addEntry(entry.entry, entry.alignment, entry.priority);
} }
} }
return this.element;
} }
private showContextMenu(e: MouseEvent): void { private showContextMenu(e: MouseEvent): void {
EventHelper.stop(e, true); EventHelper.stop(e, true);
const event = new StandardMouseEvent(e); const event = new StandardMouseEvent(e);
let actions: IAction[] | undefined = undefined;
this.contextMenuService.showContextMenu({ this.contextMenuService.showContextMenu({
getAnchor: () => { return { x: event.posx, y: event.posy }; }, getAnchor: () => ({ x: event.posx, y: event.posy }),
getActions: () => this.getContextMenuActions() getActions: () => {
actions = this.getContextMenuActions(event);
return actions;
},
onHide: () => {
if (actions) {
dispose(actions);
}
}
}); });
} }
private getContextMenuActions(): IAction[] { private getContextMenuActions(event: StandardMouseEvent): IAction[] {
const actions: IAction[] = []; const actions: Action[] = [];
// Figure out if mouse is over an entry
let categoryUnderMouse: IStatusbarEntryCategory | undefined = undefined;
for (let element: HTMLElement | null = event.target; element; element = element.parentElement) {
if (element.hasAttribute(StatusbarPart.CATEGORY_PROP)) {
categoryUnderMouse = { id: element.getAttribute(StatusbarPart.CATEGORY_PROP)!, label: element.title };
break;
}
}
if (categoryUnderMouse) {
actions.push(new HideStatusCategoryAction(categoryUnderMouse, this.viewModel));
actions.push(new Separator());
}
// TODO@Ben collect more context menu actions // Show an entry per known status item category
// .map(({ id, name, activityAction }) => (<IAction>{ const handledCategories = new Set<string>();
// id, this.viewModel.items.forEach(item => {
// label: name || id, if (!handledCategories.has(item.category.id)) {
// checked: this.isPinned(id), actions.push(new ToggleStatusCategoryVisibilityAction(item.category, this.viewModel));
// run: () => { }
// if (this.isPinned(id)) { });
// this.unpin(id);
// } else {
// this.pin(id, true);
// }
// }
// }));
// actions.push(new Separator());
actions.push(this.hideStatusBarAction); // Provide an action to hide the status bar at last
actions.push(new Separator());
actions.push(this.instantiationService.createInstance(ToggleStatusbarVisibilityAction, ToggleStatusbarVisibilityAction.ID, nls.localize('hideStatusBar', "Hide Status Bar")));
return actions; return actions;
} }
...@@ -265,23 +525,30 @@ export class StatusbarPart extends Part implements IStatusbarService { ...@@ -265,23 +525,30 @@ export class StatusbarPart extends Part implements IStatusbarService {
this.styleElement.innerHTML = `.monaco-workbench .part.statusbar > .statusbar-item.has-beak:before { border-bottom-color: ${backgroundColor}; }`; this.styleElement.innerHTML = `.monaco-workbench .part.statusbar > .statusbar-item.has-beak:before { border-bottom-color: ${backgroundColor}; }`;
} }
private doCreateStatusItem(alignment: StatusbarAlignment, priority: number = 0, ...extraClasses: string[]): HTMLElement { private doCreateStatusItem(category: IStatusbarEntryCategory, alignment: StatusbarAlignment, priority: number = 0, ...extraClasses: string[]): HTMLElement {
const el = document.createElement('div'); const itemContainer = document.createElement('div');
addClass(el, 'statusbar-item'); itemContainer.title = category.label;
addClass(itemContainer, 'statusbar-item');
if (extraClasses) { if (extraClasses) {
addClasses(el, ...extraClasses); addClasses(itemContainer, ...extraClasses);
} }
if (alignment === StatusbarAlignment.RIGHT) { if (alignment === StatusbarAlignment.RIGHT) {
addClass(el, 'right'); addClass(itemContainer, 'right');
} else { } else {
addClass(el, 'left'); addClass(itemContainer, 'left');
} }
el.setAttribute(StatusbarPart.PRIORITY_PROP, String(priority)); itemContainer.setAttribute(StatusbarPart.PRIORITY_PROP, String(priority));
el.setAttribute(StatusbarPart.ALIGNMENT_PROP, String(alignment)); itemContainer.setAttribute(StatusbarPart.ALIGNMENT_PROP, String(alignment));
itemContainer.setAttribute(StatusbarPart.CATEGORY_PROP, category.id);
if (this.viewModel.isHidden(category)) {
hide(itemContainer);
}
return el; return itemContainer;
} }
layout(width: number, height: number): void { layout(width: number, height: number): void {
...@@ -295,27 +562,20 @@ export class StatusbarPart extends Part implements IStatusbarService { ...@@ -295,27 +562,20 @@ export class StatusbarPart extends Part implements IStatusbarService {
} }
} }
let manageExtensionAction: ManageExtensionAction; class StatusbarEntryItem extends Disposable {
class StatusBarEntryItem extends Disposable {
private entryDisposables: IDisposable[] = []; private entryDisposables: IDisposable[] = [];
constructor( constructor(
private container: HTMLElement, private container: HTMLElement,
entry: IStatusbarEntry, entry: IStatusbarEntry,
@ICommandService private readonly commandService: ICommandService, @ICommandService private readonly commandService: ICommandService,
@IInstantiationService private readonly instantiationService: IInstantiationService,
@INotificationService private readonly notificationService: INotificationService, @INotificationService private readonly notificationService: INotificationService,
@ITelemetryService private readonly telemetryService: ITelemetryService, @ITelemetryService private readonly telemetryService: ITelemetryService,
@IContextMenuService private readonly contextMenuService: IContextMenuService,
@IEditorService private readonly editorService: IEditorService, @IEditorService private readonly editorService: IEditorService,
@IThemeService private readonly themeService: IThemeService @IThemeService private readonly themeService: IThemeService
) { ) {
super(); super();
if (!manageExtensionAction) {
manageExtensionAction = this.instantiationService.createInstance(ManageExtensionAction);
}
this.render(entry); this.render(entry);
} }
...@@ -355,19 +615,6 @@ class StatusBarEntryItem extends Disposable { ...@@ -355,19 +615,6 @@ class StatusBarEntryItem extends Disposable {
addClass(this.container, 'has-background-color'); addClass(this.container, 'has-background-color');
} }
// Context Menu
if (entry.extensionId) {
this.entryDisposables.push((addDisposableListener(textContainer, 'contextmenu', e => {
EventHelper.stop(e, true);
this.contextMenuService.showContextMenu({
getAnchor: () => this.container,
getActionsContext: () => entry.extensionId!.value,
getActions: () => [manageExtensionAction]
});
})));
}
this.container.appendChild(textContainer); this.container.appendChild(textContainer);
} }
...@@ -416,19 +663,6 @@ class StatusBarEntryItem extends Disposable { ...@@ -416,19 +663,6 @@ class StatusBarEntryItem extends Disposable {
} }
} }
class ManageExtensionAction extends Action {
constructor(
@ICommandService private readonly commandService: ICommandService
) {
super('statusbar.manage.extension', nls.localize('manageExtension', "Manage Extension"));
}
run(extensionId: string): Promise<any> {
return this.commandService.executeCommand('_extensions.manage', extensionId);
}
}
registerThemingParticipant((theme: ITheme, collector: ICssStyleCollector) => { registerThemingParticipant((theme: ITheme, collector: ICssStyleCollector) => {
const statusBarItemHoverBackground = theme.getColor(STATUS_BAR_ITEM_HOVER_BACKGROUND); const statusBarItemHoverBackground = theme.getColor(STATUS_BAR_ITEM_HOVER_BACKGROUND);
if (statusBarItemHoverBackground) { if (statusBarItemHoverBackground) {
......
...@@ -65,6 +65,7 @@ export class DebugStatusContribution implements IWorkbenchContribution { ...@@ -65,6 +65,7 @@ export class DebugStatusContribution implements IWorkbenchContribution {
private get entry(): IStatusbarEntry { private get entry(): IStatusbarEntry {
return { return {
category: { id: 'status.debug', label: nls.localize('status.debug', "Debug Configuration") },
text: this.getText(), text: this.getText(),
tooltip: nls.localize('selectAndStartDebug', "Select and start debug configuration"), tooltip: nls.localize('selectAndStartDebug', "Select and start debug configuration"),
command: 'workbench.action.debug.selectandstart' command: 'workbench.action.debug.selectandstart'
......
...@@ -84,6 +84,7 @@ export class ExtensionHostProfileService extends Disposable implements IExtensio ...@@ -84,6 +84,7 @@ export class ExtensionHostProfileService extends Disposable implements IExtensio
if (visible) { if (visible) {
const indicator: IStatusbarEntry = { const indicator: IStatusbarEntry = {
category: { id: 'status.profiler', label: nls.localize('status.profiler', "Extension Profiler") },
text: nls.localize('profilingExtensionHost', "$(sync~spin) Profiling Extension Host"), text: nls.localize('profilingExtensionHost', "$(sync~spin) Profiling Extension Host"),
tooltip: nls.localize('selectAndStartDebug', "Click to stop profiling."), tooltip: nls.localize('selectAndStartDebug', "Click to stop profiling."),
command: 'workbench.action.extensionHostProfilder.stop' command: 'workbench.action.extensionHostProfilder.stop'
......
...@@ -13,6 +13,7 @@ import { IConfigurationRegistry, Extensions as ConfigurationExtensions } from 'v ...@@ -13,6 +13,7 @@ import { IConfigurationRegistry, Extensions as ConfigurationExtensions } from 'v
// Register Statusbar item // Register Statusbar item
Registry.as<IStatusbarRegistry>(Extensions.Statusbar).registerStatusbarItem(new StatusbarItemDescriptor( Registry.as<IStatusbarRegistry>(Extensions.Statusbar).registerStatusbarItem(new StatusbarItemDescriptor(
FeedbackStatusbarItem, FeedbackStatusbarItem,
{ id: 'status.feedback', label: localize('status.feedback', "Send Feedback") },
StatusbarAlignment.RIGHT, StatusbarAlignment.RIGHT,
-100 /* towards the end of the right hand side */ -100 /* towards the end of the right hand side */
)); ));
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
import { IDisposable, dispose, Disposable } from 'vs/base/common/lifecycle'; import { IDisposable, dispose, Disposable } from 'vs/base/common/lifecycle';
import { IStatusbarItem } from 'vs/workbench/browser/parts/statusbar/statusbar'; import { IStatusbarItem } from 'vs/workbench/browser/parts/statusbar/statusbar';
import { FeedbackDropdown, IFeedback, IFeedbackDelegate, FEEDBACK_VISIBLE_CONFIG } from 'vs/workbench/contrib/feedback/electron-browser/feedback'; import { FeedbackDropdown, IFeedback, IFeedbackDelegate, FEEDBACK_VISIBLE_CONFIG } from 'vs/workbench/contrib/feedback/electron-browser/feedback';
import { IContextViewService, IContextMenuService } from 'vs/platform/contextview/browser/contextView'; import { IContextViewService } from 'vs/platform/contextview/browser/contextView';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import product from 'vs/platform/product/node/product'; import product from 'vs/platform/product/node/product';
import { Themable, STATUS_BAR_ITEM_HOVER_BACKGROUND } from 'vs/workbench/common/theme'; import { Themable, STATUS_BAR_ITEM_HOVER_BACKGROUND } from 'vs/workbench/common/theme';
...@@ -14,8 +14,6 @@ import { IThemeService, registerThemingParticipant, ITheme, ICssStyleCollector } ...@@ -14,8 +14,6 @@ import { IThemeService, registerThemingParticipant, ITheme, ICssStyleCollector }
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
import { IConfigurationChangeEvent, IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IConfigurationChangeEvent, IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { clearNode, EventHelper, addClass, removeClass, addDisposableListener } from 'vs/base/browser/dom'; import { clearNode, EventHelper, addClass, removeClass, addDisposableListener } from 'vs/base/browser/dom';
import { localize } from 'vs/nls';
import { Action } from 'vs/base/common/actions';
class TwitterFeedbackService implements IFeedbackDelegate { class TwitterFeedbackService implements IFeedbackDelegate {
...@@ -54,13 +52,11 @@ export class FeedbackStatusbarItem extends Themable implements IStatusbarItem { ...@@ -54,13 +52,11 @@ export class FeedbackStatusbarItem extends Themable implements IStatusbarItem {
private dropdown: FeedbackDropdown | undefined; private dropdown: FeedbackDropdown | undefined;
private enabled: boolean; private enabled: boolean;
private container: HTMLElement; private container: HTMLElement;
private hideAction: HideAction;
constructor( constructor(
@IInstantiationService private readonly instantiationService: IInstantiationService, @IInstantiationService private readonly instantiationService: IInstantiationService,
@IContextViewService private readonly contextViewService: IContextViewService, @IContextViewService private readonly contextViewService: IContextViewService,
@IWorkspaceContextService private readonly contextService: IWorkspaceContextService, @IWorkspaceContextService private readonly contextService: IWorkspaceContextService,
@IContextMenuService private readonly contextMenuService: IContextMenuService,
@IConfigurationService private readonly configurationService: IConfigurationService, @IConfigurationService private readonly configurationService: IConfigurationService,
@IThemeService themeService: IThemeService @IThemeService themeService: IThemeService
) { ) {
...@@ -68,8 +64,6 @@ export class FeedbackStatusbarItem extends Themable implements IStatusbarItem { ...@@ -68,8 +64,6 @@ export class FeedbackStatusbarItem extends Themable implements IStatusbarItem {
this.enabled = this.configurationService.getValue(FEEDBACK_VISIBLE_CONFIG); this.enabled = this.configurationService.getValue(FEEDBACK_VISIBLE_CONFIG);
this.hideAction = this._register(this.instantiationService.createInstance(HideAction));
this.registerListeners(); this.registerListeners();
} }
...@@ -95,16 +89,6 @@ export class FeedbackStatusbarItem extends Themable implements IStatusbarItem { ...@@ -95,16 +89,6 @@ export class FeedbackStatusbarItem extends Themable implements IStatusbarItem {
} }
}, true)); }, true));
// Offer context menu to hide status bar entry
this._register(addDisposableListener(this.container, 'contextmenu', e => {
EventHelper.stop(e, true);
this.contextMenuService.showContextMenu({
getAnchor: () => this.container,
getActions: () => [this.hideAction]
});
}));
return this.update(); return this.update();
} }
...@@ -143,19 +127,6 @@ export class FeedbackStatusbarItem extends Themable implements IStatusbarItem { ...@@ -143,19 +127,6 @@ export class FeedbackStatusbarItem extends Themable implements IStatusbarItem {
} }
} }
class HideAction extends Action {
constructor(
@IConfigurationService private readonly configurationService: IConfigurationService
) {
super('feedback.hide', localize('hide', "Hide"));
}
run(extensionId: string): Promise<any> {
return this.configurationService.updateValue(FEEDBACK_VISIBLE_CONFIG, false);
}
}
registerThemingParticipant((theme: ITheme, collector: ICssStyleCollector) => { registerThemingParticipant((theme: ITheme, collector: ICssStyleCollector) => {
const statusBarItemHoverBackground = theme.getColor(STATUS_BAR_ITEM_HOVER_BACKGROUND); const statusBarItemHoverBackground = theme.getColor(STATUS_BAR_ITEM_HOVER_BACKGROUND);
if (statusBarItemHoverBackground) { if (statusBarItemHoverBackground) {
......
...@@ -286,6 +286,7 @@ class MarkersStatusBarContributions extends Disposable implements IWorkbenchCont ...@@ -286,6 +286,7 @@ class MarkersStatusBarContributions extends Disposable implements IWorkbenchCont
private getMarkersItem(): IStatusbarEntry { private getMarkersItem(): IStatusbarEntry {
const markersStatistics = this.markerService.getStatistics(); const markersStatistics = this.markerService.getStatistics();
return { return {
category: { id: 'status.problems', label: localize('status.problems', "Problems") },
text: this.getMarkersText(markersStatistics), text: this.getMarkersText(markersStatistics),
tooltip: this.getMarkersTooltip(markersStatistics), tooltip: this.getMarkersTooltip(markersStatistics),
command: 'workbench.actions.view.toggleProblems' command: 'workbench.actions.view.toggleProblems'
......
...@@ -138,6 +138,7 @@ export class RemoteWindowActiveIndicator extends Disposable implements IWorkbenc ...@@ -138,6 +138,7 @@ export class RemoteWindowActiveIndicator extends Disposable implements IWorkbenc
private renderWindowIndicator(text: string, tooltip?: string, command?: string): void { private renderWindowIndicator(text: string, tooltip?: string, command?: string): void {
const properties: IStatusbarEntry = { const properties: IStatusbarEntry = {
category: { id: 'status.host', label: nls.localize('status.host', "Remote Host") },
backgroundColor: themeColorFromId(STATUS_BAR_HOST_NAME_BACKGROUND), color: themeColorFromId(STATUS_BAR_HOST_NAME_FOREGROUND), text, tooltip, command backgroundColor: themeColorFromId(STATUS_BAR_HOST_NAME_BACKGROUND), color: themeColorFromId(STATUS_BAR_HOST_NAME_FOREGROUND), text, tooltip, command
}; };
if (this.windowIndicatorEntry) { if (this.windowIndicatorEntry) {
......
...@@ -190,6 +190,7 @@ export class StatusBarController implements IWorkbenchContribution { ...@@ -190,6 +190,7 @@ export class StatusBarController implements IWorkbenchContribution {
const disposables = new DisposableStore(); const disposables = new DisposableStore();
for (const c of commands) { for (const c of commands) {
disposables.add(this.statusbarService.addEntry({ disposables.add(this.statusbarService.addEntry({
category: { id: 'status.scm', label: localize('status.scm', "Source Control") },
text: c.title, text: c.title,
tooltip: `${label} - ${c.tooltip}`, tooltip: `${label} - ${c.tooltip}`,
command: c.id, command: c.id,
......
...@@ -182,6 +182,7 @@ export class TaskStatusBarContributions extends Disposable implements IWorkbench ...@@ -182,6 +182,7 @@ export class TaskStatusBarContributions extends Disposable implements IWorkbench
} }
} else { } else {
const itemProps: IStatusbarEntry = { const itemProps: IStatusbarEntry = {
category: { id: 'status.runningTasks', label: nls.localize('status.runningTasks', "Running Tasks") },
text: `$(tools) ${tasks.length}`, text: `$(tools) ${tasks.length}`,
tooltip: nls.localize('runningTasks', "Show Running Tasks"), tooltip: nls.localize('runningTasks', "Show Running Tasks"),
command: 'workbench.action.tasks.showTasks', command: 'workbench.action.tasks.showTasks',
......
...@@ -129,6 +129,7 @@ export class ProgressService implements IProgressService { ...@@ -129,6 +129,7 @@ export class ProgressService implements IProgressService {
} }
this._globalStatusEntry = this._statusbarService.addEntry({ this._globalStatusEntry = this._statusbarService.addEntry({
category: { id: 'status.progress', label: localize('status.progress', "Progress Message") },
text: `$(sync~spin) ${text}`, text: `$(sync~spin) ${text}`,
tooltip: title tooltip: title
}, StatusbarAlignment.LEFT); }, StatusbarAlignment.LEFT);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册