提交 9b7daa87 编写于 作者: I Isidor Nikolic 提交者: GitHub

Merge pull request #27453 from Microsoft/joao/light-update

Joao/light update
......@@ -7,7 +7,8 @@
import { TPromise } from 'vs/base/common/winjs.base';
import { IChannel, eventToCall, eventFromCall } from 'vs/base/parts/ipc/common/ipc';
import Event from 'vs/base/common/event';
import Event, { Emitter } from 'vs/base/common/event';
import { onUnexpectedError } from 'vs/base/common/errors';
import { IUpdateService, IRawUpdate, State, IUpdate } from './update';
export interface IUpdateChannel extends IChannel {
......@@ -18,6 +19,7 @@ export interface IUpdateChannel extends IChannel {
call(command: 'event:onStateChange'): TPromise<void>;
call(command: 'checkForUpdates', arg: boolean): TPromise<IUpdate>;
call(command: 'quitAndInstall'): TPromise<void>;
call(command: '_getInitialState'): TPromise<State>;
call(command: string, arg?: any): TPromise<any>;
}
......@@ -34,6 +36,7 @@ export class UpdateChannel implements IUpdateChannel {
case 'event:onStateChange': return eventToCall(this.service.onStateChange);
case 'checkForUpdates': return this.service.checkForUpdates(arg);
case 'quitAndInstall': return this.service.quitAndInstall();
case '_getInitialState': return TPromise.as(this.service.state);
}
return undefined;
}
......@@ -55,14 +58,24 @@ export class UpdateChannelClient implements IUpdateService {
private _onUpdateReady = eventFromCall<IRawUpdate>(this.channel, 'event:onUpdateReady');
get onUpdateReady(): Event<IRawUpdate> { return this._onUpdateReady; }
private _onStateChange = eventFromCall<State>(this.channel, 'event:onStateChange');
get onStateChange(): Event<State> { return this._onStateChange; }
private _onRemoteStateChange = eventFromCall<State>(this.channel, 'event:onStateChange');
private _onStateChange = new Emitter<State>();
get onStateChange(): Event<State> { return this._onStateChange.event; }
private _state: State = State.Uninitialized;
get state(): State { return this._state; };
constructor(private channel: IChannel) {
constructor(private channel: IUpdateChannel) {
// always set this._state as the state changes
this.onStateChange(state => this._state = state);
channel.call('_getInitialState').done(state => {
// fire initial state
this._onStateChange.fire(state);
// fire subsequent states as they come in from remote
this._onRemoteStateChange(state => this._onStateChange.fire(state));
}, onUnexpectedError);
}
checkForUpdates(explicit: boolean): TPromise<IUpdate> {
......
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { Registry } from 'vs/platform/platform';
import { IAction } from 'vs/base/common/actions';
import { IConstructorSignature0 } from 'vs/platform/instantiation/common/instantiation';
export interface IActivity {
id: string;
name: string;
cssClass: string;
}
export interface IGlobalActivity extends IActivity {
getActions(): IAction[];
}
export const GlobalActivityExtensions = 'workbench.contributions.globalActivities';
export interface IGlobalActivityRegistry {
registerActivity(descriptor: IConstructorSignature0<IGlobalActivity>): void;
getActivities(): IConstructorSignature0<IGlobalActivity>[];
}
export class GlobalActivityRegistry implements IGlobalActivityRegistry {
private activityDescriptors = new Set<IConstructorSignature0<IGlobalActivity>>();
registerActivity(descriptor: IConstructorSignature0<IGlobalActivity>): void {
this.activityDescriptors.add(descriptor);
}
getActivities(): IConstructorSignature0<IGlobalActivity>[] {
const result: IConstructorSignature0<IGlobalActivity>[] = [];
this.activityDescriptors.forEach(d => result.push(d));
return result;
}
}
Registry.add(GlobalActivityExtensions, new GlobalActivityRegistry());
\ No newline at end of file
......@@ -20,6 +20,7 @@ import { ICommandService } from 'vs/platform/commands/common/commands';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { ViewletDescriptor } from 'vs/workbench/browser/viewlet';
import { IActivity } from 'vs/workbench/browser/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';
......@@ -31,8 +32,12 @@ export class ActivityAction extends Action {
private badge: IBadge;
private _onDidChangeBadge = new Emitter<this>();
constructor(id: string, name: string, clazz: string) {
super(id, name, clazz);
get activity(): IActivity {
return this._activity;
}
constructor(private _activity: IActivity) {
super(_activity.id, _activity.name, _activity.cssClass);
this.badge = null;
}
......@@ -74,7 +79,7 @@ export class ViewletActivityAction extends ActivityAction {
@IViewletService private viewletService: IViewletService,
@IPartService private partService: IPartService
) {
super(viewlet.id, viewlet.name, viewlet.cssClass);
super(viewlet);
}
public run(event): TPromise<any> {
......@@ -102,7 +107,15 @@ export class ViewletActivityAction extends ActivityAction {
}
}
export abstract class ThemableActivityActionItem extends BaseActionItem {
export class ActivityActionItem extends BaseActionItem {
protected $label: Builder;
protected $badge: Builder;
private $badgeContent: Builder;
protected get activity(): IActivity {
return (this._action as ActivityAction).activity;
}
constructor(
action: ActivityAction,
......@@ -112,33 +125,126 @@ export abstract class ThemableActivityActionItem extends BaseActionItem {
super(null, action, options);
this.themeService.onThemeChange(this.onThemeChange, this, this._callOnDispose);
action.onDidChangeBadge(this.handleBadgeChangeEvenet, this, this._callOnDispose);
}
protected updateStyles(): void {
const theme = this.themeService.getTheme();
// Label
if (this.$label) {
const background = theme.getColor(ACTIVITY_BAR_FOREGROUND);
this.$label.style('background-color', background ? background.toString() : null);
}
// Badge
if (this.$badgeContent) {
const badgeForeground = theme.getColor(ACTIVITY_BAR_BADGE_FOREGROUND);
const badgeBackground = theme.getColor(ACTIVITY_BAR_BADGE_BACKGROUND);
const contrastBorderColor = theme.getColor(contrastBorder);
this.$badgeContent.style('color', badgeForeground ? badgeForeground.toString() : null);
this.$badgeContent.style('background-color', badgeBackground ? badgeBackground.toString() : null);
this.$badgeContent.style('border-style', contrastBorderColor ? 'solid' : null);
this.$badgeContent.style('border-width', contrastBorderColor ? '1px' : null);
this.$badgeContent.style('border-color', contrastBorderColor ? contrastBorderColor.toString() : null);
}
}
public render(container: HTMLElement): void {
super.render(container);
container.title = this.activity.name;
// Label
this.$label = $('a.action-label').appendTo(this.builder);
if (this.activity.cssClass) {
this.$label.addClass(this.activity.cssClass);
}
this.$badge = this.builder.clone().div({ 'class': 'badge' }, (badge: Builder) => {
this.$badgeContent = badge.div({ 'class': 'badge-content' });
});
this.$badge.hide();
this.updateStyles();
}
private onThemeChange(theme: ITheme): void {
this.updateStyles();
}
protected abstract updateStyles(): void;
public setBadge(badge: IBadge): void {
this.updateBadge(badge);
}
protected updateBadge(badge: IBadge): void {
this.$badgeContent.empty();
this.$badge.hide();
if (badge) {
// Number
if (badge instanceof NumberBadge) {
if (badge.number) {
this.$badgeContent.text(badge.number > 99 ? '99+' : badge.number.toString());
this.$badge.show();
}
}
// Text
else if (badge instanceof TextBadge) {
this.$badgeContent.text(badge.text);
this.$badge.show();
}
// Text
else if (badge instanceof IconBadge) {
this.$badge.show();
}
// Progress
else if (badge instanceof ProgressBadge) {
this.$badge.show();
}
this.$label.attr('aria-label', `${this.activity.name} - ${badge.getDescription()}`);
}
}
private handleBadgeChangeEvenet(): void {
const action = this.getAction();
if (action instanceof ActivityAction) {
this.updateBadge(action.getBadge());
}
}
public dispose(): void {
super.dispose();
this.$badge.destroy();
}
}
export class ActivityActionItem extends ThemableActivityActionItem {
export class ViewletActionItem extends ActivityActionItem {
private static manageExtensionAction: ManageExtensionAction;
private static toggleViewletPinnedAction: ToggleViewletPinnedAction;
private static draggedViewlet: ViewletDescriptor;
private $container: Builder;
private $label: Builder;
private name: string;
private _keybinding: string;
private cssClass: string;
private $badge: Builder;
private $badgeContent: Builder;
private mouseUpTimeout: number;
private get viewlet(): ViewletDescriptor {
return this.action.activity as ViewletDescriptor;
}
constructor(
action: ActivityAction,
private viewlet: ViewletDescriptor,
private action: ViewletActivityAction,
@IContextMenuService private contextMenuService: IContextMenuService,
@IActivityBarService private activityBarService: IActivityBarService,
@IKeybindingService private keybindingService: IKeybindingService,
......@@ -148,42 +254,14 @@ export class ActivityActionItem extends ThemableActivityActionItem {
super(action, { draggable: true }, themeService);
this.cssClass = action.class;
this.name = viewlet.name;
this._keybinding = this.getKeybindingLabel(viewlet.id);
if (!ActivityActionItem.manageExtensionAction) {
ActivityActionItem.manageExtensionAction = instantiationService.createInstance(ManageExtensionAction);
}
if (!ActivityActionItem.toggleViewletPinnedAction) {
ActivityActionItem.toggleViewletPinnedAction = instantiationService.createInstance(ToggleViewletPinnedAction, void 0);
}
this._keybinding = this.getKeybindingLabel(this.viewlet.id);
action.onDidChangeBadge(this.handleBadgeChangeEvenet, this, this._callOnDispose);
}
protected updateStyles(): void {
const theme = this.themeService.getTheme();
// Label
if (this.$label) {
const background = theme.getColor(ACTIVITY_BAR_FOREGROUND);
this.$label.style('background-color', background ? background.toString() : null);
if (!ViewletActionItem.manageExtensionAction) {
ViewletActionItem.manageExtensionAction = instantiationService.createInstance(ManageExtensionAction);
}
// Badge
if (this.$badgeContent) {
const badgeForeground = theme.getColor(ACTIVITY_BAR_BADGE_FOREGROUND);
const badgeBackground = theme.getColor(ACTIVITY_BAR_BADGE_BACKGROUND);
const contrastBorderColor = theme.getColor(contrastBorder);
this.$badgeContent.style('color', badgeForeground ? badgeForeground.toString() : null);
this.$badgeContent.style('background-color', badgeBackground ? badgeBackground.toString() : null);
this.$badgeContent.style('border-style', contrastBorderColor ? 'solid' : null);
this.$badgeContent.style('border-width', contrastBorderColor ? '1px' : null);
this.$badgeContent.style('border-color', contrastBorderColor ? contrastBorderColor.toString() : null);
if (!ViewletActionItem.toggleViewletPinnedAction) {
ViewletActionItem.toggleViewletPinnedAction = instantiationService.createInstance(ToggleViewletPinnedAction, void 0);
}
}
......@@ -240,7 +318,7 @@ export class ActivityActionItem extends ThemableActivityActionItem {
// Drag enter
let counter = 0; // see https://github.com/Microsoft/vscode/issues/14470
this.$container.on(DOM.EventType.DRAG_ENTER, (e: DragEvent) => {
const draggedViewlet = ActivityActionItem.getDraggedViewlet();
const draggedViewlet = ViewletActionItem.getDraggedViewlet();
if (draggedViewlet && draggedViewlet.id !== this.viewlet.id) {
counter++;
this.updateFromDragging(container, true);
......@@ -249,7 +327,7 @@ export class ActivityActionItem extends ThemableActivityActionItem {
// Drag leave
this.$container.on(DOM.EventType.DRAG_LEAVE, (e: DragEvent) => {
const draggedViewlet = ActivityActionItem.getDraggedViewlet();
const draggedViewlet = ViewletActionItem.getDraggedViewlet();
if (draggedViewlet) {
counter--;
if (counter === 0) {
......@@ -260,12 +338,12 @@ export class ActivityActionItem extends ThemableActivityActionItem {
// Drag end
this.$container.on(DOM.EventType.DRAG_END, (e: DragEvent) => {
const draggedViewlet = ActivityActionItem.getDraggedViewlet();
const draggedViewlet = ViewletActionItem.getDraggedViewlet();
if (draggedViewlet) {
counter = 0;
this.updateFromDragging(container, false);
ActivityActionItem.clearDraggedViewlet();
ViewletActionItem.clearDraggedViewlet();
}
});
......@@ -273,34 +351,21 @@ export class ActivityActionItem extends ThemableActivityActionItem {
this.$container.on(DOM.EventType.DROP, (e: DragEvent) => {
DOM.EventHelper.stop(e, true);
const draggedViewlet = ActivityActionItem.getDraggedViewlet();
const draggedViewlet = ViewletActionItem.getDraggedViewlet();
if (draggedViewlet && draggedViewlet.id !== this.viewlet.id) {
this.updateFromDragging(container, false);
ActivityActionItem.clearDraggedViewlet();
ViewletActionItem.clearDraggedViewlet();
this.activityBarService.move(draggedViewlet.id, this.viewlet.id);
}
});
// Label
this.$label = $('a.action-label').appendTo(this.builder);
if (this.cssClass) {
this.$label.addClass(this.cssClass);
}
// Badge
this.$badge = this.builder.div({ 'class': 'badge' }, (badge: Builder) => {
this.$badgeContent = badge.div({ 'class': 'badge-content' });
});
this.$badge.hide();
// Keybinding
this.keybinding = this._keybinding; // force update
// Activate on drag over to reveal targets
[this.$badge, this.$label].forEach(b => new DelayedDragHandler(b.getHTMLElement(), () => {
if (!ActivityActionItem.getDraggedViewlet() && !this.getAction().checked) {
if (!ViewletActionItem.getDraggedViewlet() && !this.getAction().checked) {
this.getAction().run();
}
}));
......@@ -316,29 +381,29 @@ export class ActivityActionItem extends ThemableActivityActionItem {
}
public static getDraggedViewlet(): ViewletDescriptor {
return ActivityActionItem.draggedViewlet;
return ViewletActionItem.draggedViewlet;
}
private setDraggedViewlet(viewlet: ViewletDescriptor): void {
ActivityActionItem.draggedViewlet = viewlet;
ViewletActionItem.draggedViewlet = viewlet;
}
public static clearDraggedViewlet(): void {
ActivityActionItem.draggedViewlet = void 0;
ViewletActionItem.draggedViewlet = void 0;
}
private showContextMenu(container: HTMLElement): void {
const actions: Action[] = [ActivityActionItem.toggleViewletPinnedAction];
const actions: Action[] = [ViewletActionItem.toggleViewletPinnedAction];
if (this.viewlet.extensionId) {
actions.push(new Separator());
actions.push(ActivityActionItem.manageExtensionAction);
actions.push(ViewletActionItem.manageExtensionAction);
}
const isPinned = this.activityBarService.isPinned(this.viewlet.id);
if (isPinned) {
ActivityActionItem.toggleViewletPinnedAction.label = nls.localize('removeFromActivityBar', "Remove from Activity Bar");
ViewletActionItem.toggleViewletPinnedAction.label = nls.localize('removeFromActivityBar', "Remove from Activity Bar");
} else {
ActivityActionItem.toggleViewletPinnedAction.label = nls.localize('keepInActivityBar', "Keep in Activity Bar");
ViewletActionItem.toggleViewletPinnedAction.label = nls.localize('keepInActivityBar', "Keep in Activity Bar");
}
this.contextMenuService.showContextMenu({
......@@ -352,10 +417,6 @@ export class ActivityActionItem extends ThemableActivityActionItem {
this.$container.domFocus();
}
public setBadge(badge: IBadge): void {
this.updateBadge(badge);
}
public set keybinding(keybinding: string) {
this._keybinding = keybinding;
......@@ -365,49 +426,15 @@ export class ActivityActionItem extends ThemableActivityActionItem {
let title: string;
if (keybinding) {
title = nls.localize('titleKeybinding', "{0} ({1})", this.name, keybinding);
title = nls.localize('titleKeybinding', "{0} ({1})", this.activity.name, keybinding);
} else {
title = this.name;
title = this.activity.name;
}
this.$label.title(title);
this.$badge.title(title);
}
private updateBadge(badge: IBadge): void {
this.$badgeContent.empty();
this.$badge.hide();
if (badge) {
// Number
if (badge instanceof NumberBadge) {
if (badge.number) {
this.$badgeContent.text(badge.number > 99 ? '99+' : badge.number.toString());
this.$badge.show();
}
}
// Text
else if (badge instanceof TextBadge) {
this.$badgeContent.text(badge.text);
this.$badge.show();
}
// Text
else if (badge instanceof IconBadge) {
this.$badge.show();
}
// Progress
else if (badge instanceof ProgressBadge) {
this.$badge.show();
}
this.$label.attr('aria-label', `${this.name} - ${badge.getDescription()}`);
}
}
protected _updateClass(): void {
if (this.cssClass) {
this.$badge.removeClass(this.cssClass);
......@@ -425,13 +452,6 @@ export class ActivityActionItem extends ThemableActivityActionItem {
}
}
private handleBadgeChangeEvenet(): void {
const action = this.getAction();
if (action instanceof ActivityAction) {
this.updateBadge(action.getBadge());
}
}
protected _updateEnabled(): void {
if (this.getAction().enabled) {
this.builder.removeClass('disabled');
......@@ -443,13 +463,12 @@ export class ActivityActionItem extends ThemableActivityActionItem {
public dispose(): void {
super.dispose();
ActivityActionItem.clearDraggedViewlet();
ViewletActionItem.clearDraggedViewlet();
if (this.mouseUpTimeout) {
clearTimeout(this.mouseUpTimeout);
}
this.$badge.destroy();
this.$label.destroy();
}
}
......@@ -459,7 +478,11 @@ export class ViewletOverflowActivityAction extends ActivityAction {
constructor(
private showMenu: () => void
) {
super('activitybar.additionalViewlets.action', nls.localize('additionalViews', "Additional Views"), 'toggle-more');
super({
id: 'activitybar.additionalViewlets.action',
name: nls.localize('additionalViews', "Additional Views"),
cssClass: 'toggle-more'
});
}
public run(event): TPromise<any> {
......@@ -469,8 +492,8 @@ export class ViewletOverflowActivityAction extends ActivityAction {
}
}
export class ViewletOverflowActivityActionItem extends ThemableActivityActionItem {
private $label: Builder;
export class ViewletOverflowActivityActionItem extends ActivityActionItem {
private name: string;
private cssClass: string;
private actions: OpenViewletAction[];
......
......@@ -15,9 +15,11 @@ import { Builder, $, Dimension } from 'vs/base/browser/builder';
import { Action } from 'vs/base/common/actions';
import { ActionsOrientation, ActionBar, IActionItem, Separator } from 'vs/base/browser/ui/actionbar/actionbar';
import { ViewletDescriptor } from 'vs/workbench/browser/viewlet';
import { IGlobalActivity, GlobalActivityExtensions, IGlobalActivityRegistry } from 'vs/workbench/browser/activity';
import { Registry } from 'vs/platform/platform';
import { Part } from 'vs/workbench/browser/part';
import { IViewlet } from 'vs/workbench/common/viewlet';
import { ToggleViewletPinnedAction, ViewletActivityAction, ActivityAction, ActivityActionItem, ViewletOverflowActivityAction, ViewletOverflowActivityActionItem } from 'vs/workbench/browser/parts/activitybar/activitybarActions';
import { ToggleViewletPinnedAction, ViewletActivityAction, ActivityAction, ActivityActionItem, ViewletActionItem, ViewletOverflowActivityAction, ViewletOverflowActivityActionItem } from 'vs/workbench/browser/parts/activitybar/activitybarActions';
import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet';
import { IActivityBarService, IBadge } from 'vs/workbench/services/activity/common/activityBarService';
import { IPartService, Position as SideBarPosition } from 'vs/workbench/services/part/common/partService';
......@@ -27,7 +29,7 @@ import { IStorageService } from 'vs/platform/storage/common/storage';
import { Scope as MementoScope } from 'vs/workbench/common/memento';
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
import { StandardMouseEvent } from 'vs/base/browser/mouseEvent';
import { dispose, IDisposable } from 'vs/base/common/lifecycle';
import { dispose, IDisposable, toDisposable } from 'vs/base/common/lifecycle';
import { ToggleActivityBarVisibilityAction } from 'vs/workbench/browser/actions/toggleActivityBarVisibility';
import { IThemeService } from 'vs/platform/theme/common/themeService';
import { ACTIVITY_BAR_BACKGROUND, ACTIVITY_BAR_BORDER } from 'vs/workbench/common/theme';
......@@ -38,6 +40,40 @@ interface IViewletActivity {
clazz: string;
}
class GlobalActivityAction extends ActivityAction {
constructor(activity: IGlobalActivity) {
super(activity);
}
}
class GlobalActivityActionItem extends ActivityActionItem {
constructor(
action: GlobalActivityAction,
@IThemeService themeService: IThemeService,
@IContextMenuService protected contextMenuService: IContextMenuService
) {
super(action, { draggable: false }, themeService);
}
onClick(e: MouseEvent): void {
const globalAction = this._action as GlobalActivityAction;
const activity = globalAction.activity as IGlobalActivity;
const actions = activity.getActions();
const event = new StandardMouseEvent(e);
event.stopPropagation();
event.preventDefault();
this.contextMenuService.showContextMenu({
getAnchor: () => ({ x: event.posx, y: event.posy }),
getActions: () => TPromise.as(actions),
onHide: () => dispose(actions)
});
}
}
export class ActivitybarPart extends Part implements IActivityBarService {
private static readonly ACTIVITY_ACTION_HEIGHT = 50;
......@@ -48,9 +84,11 @@ export class ActivitybarPart extends Part implements IActivityBarService {
private dimension: Dimension;
private viewletSwitcherBar: ActionBar;
private activityActionBar: ActionBar;
private viewletOverflowAction: ViewletOverflowActivityAction;
private viewletOverflowActionItem: ViewletOverflowActivityActionItem;
private globalActivityIdToActions: { [globalActivityId: string]: GlobalActivityAction; };
private viewletIdToActions: { [viewletId: string]: ActivityAction; };
private viewletIdToActionItems: { [viewletId: string]: IActionItem; };
private viewletIdToActivityStack: { [viewletId: string]: IViewletActivity[]; };
......@@ -71,6 +109,7 @@ export class ActivitybarPart extends Part implements IActivityBarService {
) {
super(id, { hasTitle: false }, themeService);
this.globalActivityIdToActions = Object.create(null);
this.viewletIdToActionItems = Object.create(null);
this.viewletIdToActions = Object.create(null);
this.viewletIdToActivityStack = Object.create(null);
......@@ -123,6 +162,21 @@ export class ActivitybarPart extends Part implements IActivityBarService {
}
}
public showGlobalActivity(globalActivityId: string, badge: IBadge): IDisposable {
if (!badge) {
throw illegalArgument('badge');
}
const action = this.globalActivityIdToActions[globalActivityId];
if (!action) {
throw illegalArgument('globalActivityId');
}
action.setBadge(badge);
return toDisposable(() => action.setBadge(undefined));
}
public showActivity(viewletId: string, badge: IBadge, clazz?: string): IDisposable {
if (!badge) {
throw illegalArgument('badge');
......@@ -180,6 +234,9 @@ export class ActivitybarPart extends Part implements IActivityBarService {
// Top Actionbar with action items for each viewlet action
this.createViewletSwitcher($result.clone());
// Top Actionbar with action items for each viewlet action
this.createGlobalActivityActionBar($result.getHTMLElement());
// Contextmenu for viewlets
$(parent).on('contextmenu', (e: MouseEvent) => {
DOM.EventHelper.stop(e, true);
......@@ -189,11 +246,11 @@ export class ActivitybarPart extends Part implements IActivityBarService {
// Allow to drop at the end to move viewlet to the end
$(parent).on(DOM.EventType.DROP, (e: DragEvent) => {
const draggedViewlet = ActivityActionItem.getDraggedViewlet();
const draggedViewlet = ViewletActionItem.getDraggedViewlet();
if (draggedViewlet) {
DOM.EventHelper.stop(e, true);
ActivityActionItem.clearDraggedViewlet();
ViewletActionItem.clearDraggedViewlet();
const targetId = this.pinnedViewlets[this.pinnedViewlets.length - 1];
if (targetId !== draggedViewlet.id) {
......@@ -252,6 +309,26 @@ export class ActivitybarPart extends Part implements IActivityBarService {
this.extensionService.onReady().then(() => this.updateViewletSwitcher());
}
private createGlobalActivityActionBar(container: HTMLElement): void {
const activityRegistry = Registry.as<IGlobalActivityRegistry>(GlobalActivityExtensions);
const descriptors = activityRegistry.getActivities();
const actions = descriptors
.map(d => this.instantiationService.createInstance(d))
.map(a => new GlobalActivityAction(a));
this.activityActionBar = new ActionBar(container, {
actionItemProvider: a => this.instantiationService.createInstance(GlobalActivityActionItem, a),
orientation: ActionsOrientation.VERTICAL,
ariaLabel: nls.localize('globalActions', "Global Actions"),
animated: false
});
actions.forEach(a => {
this.globalActivityIdToActions[a.id] = a;
this.activityActionBar.push(a);
});
}
private updateViewletSwitcher() {
let viewletsToShow = this.getPinnedViewlets();
......@@ -371,7 +448,7 @@ export class ActivitybarPart extends Part implements IActivityBarService {
private toAction(viewlet: ViewletDescriptor): ActivityAction {
const action = this.instantiationService.createInstance(ViewletActivityAction, viewlet);
this.viewletIdToActionItems[action.id] = this.instantiationService.createInstance(ActivityActionItem, action, viewlet);
this.viewletIdToActionItems[action.id] = this.instantiationService.createInstance(ViewletActionItem, action);
this.viewletIdToActions[viewlet.id] = action;
return action;
......
......@@ -9,6 +9,9 @@
.monaco-workbench > .activitybar > .content {
height: 100%;
display: flex;
flex-direction: column;
justify-content: space-between;
}
.monaco-workbench > .activitybar > .content .monaco-action-bar {
......
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
.update-activity {
-webkit-mask: url('update.svg') no-repeat 50% 50%;
-webkit-mask-size: 22px;
}
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><g fill="#424242"><path d="M12.714 9.603c-.07.207-.15.407-.246.601l1.017 2.139c-.335.424-.718.807-1.142 1.143l-2.14-1.018c-.193.097-.394.176-.601.247l-.795 2.235c-.265.03-.534.05-.807.05-.272 0-.541-.02-.806-.05l-.795-2.235c-.207-.071-.408-.15-.602-.247l-2.14 1.017c-.424-.336-.807-.719-1.143-1.143l1.017-2.139c-.094-.193-.175-.393-.245-.6l-2.236-.796c-.03-.265-.05-.534-.05-.807s.02-.542.05-.807l2.236-.795c.07-.207.15-.407.246-.601l-1.016-2.139c.336-.423.719-.807 1.143-1.142l2.14 1.017c.193-.096.394-.176.602-.247l.793-2.236c.265-.03.534-.05.806-.05.273 0 .542.02.808.05l.795 2.236c.207.07.407.15.601.246l2.14-1.017c.424.335.807.719 1.142 1.142l-1.017 2.139c.096.194.176.394.246.601l2.236.795c.029.266.049.535.049.808s-.02.542-.05.807l-2.236.796zm-4.714-4.603c-1.657 0-3 1.343-3 3s1.343 3 3 3 3-1.343 3-3-1.343-3-3-3z"/><circle cx="8" cy="8" r="1.5"/></g></svg>
\ No newline at end of file
......@@ -6,20 +6,31 @@
'use strict';
import * as nls from 'vs/nls';
import 'vs/css!./media/update.contribution';
import { Registry } from 'vs/platform/platform';
import product from 'vs/platform/node/product';
import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions';
import { ShowCurrentReleaseNotesAction, UpdateContribution } from 'vs/workbench/parts/update/electron-browser/update';
import { ReleaseNotesEditor } from 'vs/workbench/parts/update/electron-browser/releaseNotesEditor';
import { ReleaseNotesInput } from 'vs/workbench/parts/update/electron-browser/releaseNotesInput';
import { EditorDescriptor } from 'vs/workbench/browser/parts/editor/baseEditor';
import { IGlobalActivityRegistry, GlobalActivityExtensions } from 'vs/workbench/browser/activity';
import { IEditorRegistry, Extensions as EditorExtensions } from 'vs/workbench/common/editor';
import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
import { IWorkbenchActionRegistry, Extensions as ActionExtensions } from 'vs/workbench/common/actionRegistry';
import { SyncActionDescriptor } from 'vs/platform/actions/common/actions';
import { IConfigurationRegistry, Extensions as ConfigurationExtensions } from 'vs/platform/configuration/common/configurationRegistry';
import { ShowCurrentReleaseNotesAction, ProductContribution, UpdateContribution, LightUpdateContribution } from './update';
Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench)
.registerWorkbenchContribution(UpdateContribution);
.registerWorkbenchContribution(ProductContribution);
if (product.quality === 'insider') {
Registry.as<IGlobalActivityRegistry>(GlobalActivityExtensions)
.registerActivity(LightUpdateContribution);
} else {
Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench)
.registerWorkbenchContribution(UpdateContribution);
}
// Editor
const editorDescriptor = new EditorDescriptor(
......@@ -35,7 +46,6 @@ Registry.as<IEditorRegistry>(EditorExtensions.Editors)
Registry.as<IWorkbenchActionRegistry>(ActionExtensions.WorkbenchActions)
.registerWorkbenchAction(new SyncActionDescriptor(ShowCurrentReleaseNotesAction, ShowCurrentReleaseNotesAction.ID, ShowCurrentReleaseNotesAction.LABEL), 'Open Release Notes');
// Configuration: Update
const configurationRegistry = <IConfigurationRegistry>Registry.as(ConfigurationExtensions.Configuration);
configurationRegistry.registerConfiguration({
......
......@@ -8,24 +8,28 @@
import nls = require('vs/nls');
import severity from 'vs/base/common/severity';
import { TPromise } from 'vs/base/common/winjs.base';
import { Action } from 'vs/base/common/actions';
import { IAction, Action } from 'vs/base/common/actions';
import { Separator } from 'vs/base/browser/ui/actionbar/actionbar';
import { IMessageService, CloseAction, Severity } from 'vs/platform/message/common/message';
import pkg from 'vs/platform/node/package';
import product from 'vs/platform/node/product';
import URI from 'vs/base/common/uri';
import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService';
import { IActivityBarService, TextBadge } from 'vs/workbench/services/activity/common/activityBarService';
import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
import { ReleaseNotesInput } from 'vs/workbench/parts/update/electron-browser/releaseNotesInput';
import { IGlobalActivity } from 'vs/workbench/browser/activity';
import { IRequestService } from 'vs/platform/request/node/request';
import { asText } from 'vs/base/node/request';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { KeybindingIO } from 'vs/workbench/services/keybinding/common/keybindingIO';
import { IOpenerService } from 'vs/platform/opener/common/opener';
import { ICommandService } from 'vs/platform/commands/common/commands';
import { IWorkbenchContribution } from 'vs/workbench/common/contributions';
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
import { IUpdateService } from 'vs/platform/update/common/update';
import { IUpdateService, State as UpdateState } from 'vs/platform/update/common/update';
import * as semver from 'semver';
import { OS } from 'vs/base/common/platform';
import { OS, isLinux, isWindows } from 'vs/base/common/platform';
class ApplyUpdateAction extends Action {
constructor( @IUpdateService private updateService: IUpdateService) {
......@@ -189,24 +193,22 @@ const LinkAction = (id: string, message: string, licenseUrl: string) => new Acti
() => { window.open(licenseUrl); return TPromise.as(null); }
);
export class UpdateContribution implements IWorkbenchContribution {
export class ProductContribution implements IWorkbenchContribution {
private static KEY = 'releaseNotes/lastVersion';
getId() { return 'vs.update'; }
getId() { return 'vs.product'; }
constructor(
@IStorageService storageService: IStorageService,
@IInstantiationService instantiationService: IInstantiationService,
@IMessageService messageService: IMessageService,
@IUpdateService updateService: IUpdateService,
@IWorkbenchEditorService editorService: IWorkbenchEditorService
) {
const lastVersion = storageService.get(UpdateContribution.KEY, StorageScope.GLOBAL, '');
const lastVersion = storageService.get(ProductContribution.KEY, StorageScope.GLOBAL, '');
// was there an update?
// was there an update? if so, open release notes
if (product.releaseNotesUrl && lastVersion && pkg.version !== lastVersion) {
instantiationService.invokeFunction(loadReleaseNotes, pkg.version)
.then(
instantiationService.invokeFunction(loadReleaseNotes, pkg.version).then(
text => editorService.openEditor(instantiationService.createInstance(ReleaseNotesInput, pkg.version, text), { pinned: true }),
() => {
messageService.show(Severity.Info, {
......@@ -230,8 +232,19 @@ export class UpdateContribution implements IWorkbenchContribution {
});
}
storageService.store(UpdateContribution.KEY, pkg.version, StorageScope.GLOBAL);
storageService.store(ProductContribution.KEY, pkg.version, StorageScope.GLOBAL);
}
}
export class UpdateContribution implements IWorkbenchContribution {
getId() { return 'vs.update'; }
constructor(
@IInstantiationService instantiationService: IInstantiationService,
@IMessageService messageService: IMessageService,
@IUpdateService updateService: IUpdateService
) {
updateService.onUpdateReady(update => {
const applyUpdateAction = instantiationService.createInstance(ApplyUpdateAction);
const releaseNotesAction = instantiationService.createInstance(ShowReleaseNotesAction, false, update.version);
......@@ -262,4 +275,69 @@ export class UpdateContribution implements IWorkbenchContribution {
updateService.onError(err => messageService.show(severity.Error, err));
}
}
export class LightUpdateContribution implements IGlobalActivity {
get id() { return 'vs.update'; }
get name() { return ''; }
get cssClass() { return 'update-activity'; }
constructor(
@IStorageService storageService: IStorageService,
@ICommandService private commandService: ICommandService,
@IInstantiationService instantiationService: IInstantiationService,
@IMessageService messageService: IMessageService,
@IUpdateService private updateService: IUpdateService,
@IWorkbenchEditorService editorService: IWorkbenchEditorService,
@IActivityBarService activityBarService: IActivityBarService
) {
this.updateService.onUpdateReady(() => {
const badge = new TextBadge('\u21e9', () => nls.localize('updateIsReady', "New update available."));
activityBarService.showGlobalActivity(this.id, badge);
});
this.updateService.onError(err => messageService.show(severity.Error, err));
}
getActions(): IAction[] {
return [
new Action('showCommandPalette', nls.localize('commandPalette', "Command Palette..."), undefined, true, () => this.commandService.executeCommand('workbench.action.showCommands')),
new Separator(),
new Action('openKeybindings', nls.localize('settings', "Settings"), null, true, () => this.commandService.executeCommand('workbench.action.openGlobalSettings')),
new Action('openSettings', nls.localize('keyboardShortcuts', "Keyboard Shortcuts"), null, true, () => this.commandService.executeCommand('workbench.action.openGlobalKeybindings')),
new Separator(),
this.getUpdateAction()
];
}
private getUpdateAction(): IAction {
switch (this.updateService.state) {
case UpdateState.Uninitialized:
return new Action('update.notavailable', nls.localize('not available', "Updates Not Available"), undefined, false);
case UpdateState.CheckingForUpdate:
return new Action('update.checking', nls.localize('checkingForUpdates', "Checking For Updates..."), undefined, false);
case UpdateState.UpdateAvailable:
if (isLinux) {
return new Action('update.linux.available', nls.localize('DownloadUpdate', "Download Available Update"), undefined, true, () =>
this.updateService.quitAndInstall());
}
const updateAvailableLabel = isWindows
? nls.localize('DownloadingUpdate', "Downloading Update...")
: nls.localize('InstallingUpdate', "Installing Update...");
return new Action('update.available', updateAvailableLabel, undefined, false);
case UpdateState.UpdateDownloaded:
return new Action('update.restart', nls.localize('restartToUpdate', "Restart To Update..."), undefined, true, () =>
this.updateService.quitAndInstall());
default:
return new Action('update.check', nls.localize('checkForUpdates', "Check For Updates..."), undefined, this.updateService.state === UpdateState.Idle, () =>
this.updateService.checkForUpdates(true));
}
}
}
\ No newline at end of file
......@@ -63,6 +63,11 @@ export const IActivityBarService = createDecorator<IActivityBarService>('activit
export interface IActivityBarService {
_serviceBrand: any;
/**
* Show activity in the activitybar for the given global activity.
*/
showGlobalActivity(globalActivityId: string, badge: IBadge): IDisposable;
/**
* Show activity in the activitybar for the given viewlet.
*/
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册