mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-04-01 09:30:31 -04:00
Merge from master
This commit is contained in:
@@ -5,19 +5,20 @@
|
||||
|
||||
import 'vs/css!./media/views';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { TPromise } from 'vs/base/common/winjs.base';
|
||||
import { IViewsService, ViewsRegistry, IViewsViewlet, ViewContainer, IViewDescriptor, IViewContainersRegistry, Extensions as ViewContainerExtensions, TEST_VIEW_CONTAINER_ID, IView } from 'vs/workbench/common/views';
|
||||
import { IViewsService, ViewsRegistry, IViewsViewlet, ViewContainer, IViewDescriptor, IViewContainersRegistry, Extensions as ViewContainerExtensions, IView, IViewDescriptorCollection } from 'vs/workbench/common/views';
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { ViewletRegistry, Extensions as ViewletExtensions } from 'vs/workbench/browser/viewlet';
|
||||
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
|
||||
import { ILifecycleService, LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle';
|
||||
import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet';
|
||||
import { IContextKeyService, IContextKeyChangeEvent, IReadableSet } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { IContextKeyService, IContextKeyChangeEvent, IReadableSet, IContextKey, RawContextKey, ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { Event, chain, filterEvent, Emitter } from 'vs/base/common/event';
|
||||
import { sortedDiff, firstIndex, move } from 'vs/base/common/arrays';
|
||||
import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace';
|
||||
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
|
||||
import { isUndefinedOrNull } from 'vs/base/common/types';
|
||||
import { MenuId, MenuRegistry, ICommandAction } from 'vs/platform/actions/common/actions';
|
||||
import { CommandsRegistry } from 'vs/platform/commands/common/commands';
|
||||
import { localize } from 'vs/nls';
|
||||
import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
|
||||
import { values } from 'vs/base/common/map';
|
||||
|
||||
function filterViewEvent(container: ViewContainer, event: Event<IViewDescriptor[]>): Event<IViewDescriptor[]> {
|
||||
return chain(event)
|
||||
@@ -63,20 +64,24 @@ interface IViewItem {
|
||||
active: boolean;
|
||||
}
|
||||
|
||||
class ViewDescriptorCollection extends Disposable {
|
||||
class ViewDescriptorCollection extends Disposable implements IViewDescriptorCollection {
|
||||
|
||||
private contextKeys = new CounterSet<string>();
|
||||
private items: IViewItem[] = [];
|
||||
|
||||
private _onDidChange = this._register(new Emitter<void>());
|
||||
readonly onDidChange: Event<void> = this._onDidChange.event;
|
||||
private _onDidChange: Emitter<{ added: IViewDescriptor[], removed: IViewDescriptor[] }> = this._register(new Emitter<{ added: IViewDescriptor[], removed: IViewDescriptor[] }>());
|
||||
readonly onDidChangeActiveViews: Event<{ added: IViewDescriptor[], removed: IViewDescriptor[] }> = this._onDidChange.event;
|
||||
|
||||
get viewDescriptors(): IViewDescriptor[] {
|
||||
get activeViewDescriptors(): IViewDescriptor[] {
|
||||
return this.items
|
||||
.filter(i => i.active)
|
||||
.map(i => i.viewDescriptor);
|
||||
}
|
||||
|
||||
get allViewDescriptors(): IViewDescriptor[] {
|
||||
return this.items.map(i => i.viewDescriptor);
|
||||
}
|
||||
|
||||
constructor(
|
||||
container: ViewContainer,
|
||||
@IContextKeyService private contextKeyService: IContextKeyService
|
||||
@@ -95,7 +100,7 @@ class ViewDescriptorCollection extends Disposable {
|
||||
}
|
||||
|
||||
private onViewsRegistered(viewDescriptors: IViewDescriptor[]): any {
|
||||
let fireChangeEvent = false;
|
||||
const added: IViewDescriptor[] = [];
|
||||
|
||||
for (const viewDescriptor of viewDescriptors) {
|
||||
const item = {
|
||||
@@ -112,17 +117,17 @@ class ViewDescriptorCollection extends Disposable {
|
||||
}
|
||||
|
||||
if (item.active) {
|
||||
fireChangeEvent = true;
|
||||
added.push(viewDescriptor);
|
||||
}
|
||||
}
|
||||
|
||||
if (fireChangeEvent) {
|
||||
this._onDidChange.fire();
|
||||
if (added.length) {
|
||||
this._onDidChange.fire({ added, removed: [] });
|
||||
}
|
||||
}
|
||||
|
||||
private onViewsDeregistered(viewDescriptors: IViewDescriptor[]): any {
|
||||
let fireChangeEvent = false;
|
||||
const removed: IViewDescriptor[] = [];
|
||||
|
||||
for (const viewDescriptor of viewDescriptors) {
|
||||
const index = firstIndex(this.items, i => i.viewDescriptor.id === viewDescriptor.id);
|
||||
@@ -141,30 +146,35 @@ class ViewDescriptorCollection extends Disposable {
|
||||
}
|
||||
|
||||
if (item.active) {
|
||||
fireChangeEvent = true;
|
||||
removed.push(viewDescriptor);
|
||||
}
|
||||
}
|
||||
|
||||
if (fireChangeEvent) {
|
||||
this._onDidChange.fire();
|
||||
if (removed.length) {
|
||||
this._onDidChange.fire({ added: [], removed });
|
||||
}
|
||||
}
|
||||
|
||||
private onContextChanged(event: IContextKeyChangeEvent): any {
|
||||
let fireChangeEvent = false;
|
||||
const removed: IViewDescriptor[] = [];
|
||||
const added: IViewDescriptor[] = [];
|
||||
|
||||
for (const item of this.items) {
|
||||
const active = this.isViewDescriptorActive(item.viewDescriptor);
|
||||
|
||||
if (item.active !== active) {
|
||||
fireChangeEvent = true;
|
||||
if (active) {
|
||||
added.push(item.viewDescriptor);
|
||||
} else {
|
||||
removed.push(item.viewDescriptor);
|
||||
}
|
||||
}
|
||||
|
||||
item.active = active;
|
||||
}
|
||||
|
||||
if (fireChangeEvent) {
|
||||
this._onDidChange.fire();
|
||||
if (added.length || removed.length) {
|
||||
this._onDidChange.fire({ added, removed });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -208,14 +218,14 @@ export class ContributableViewsModel extends Disposable {
|
||||
|
||||
constructor(
|
||||
container: ViewContainer,
|
||||
contextKeyService: IContextKeyService,
|
||||
viewsService: IViewsService,
|
||||
protected viewStates = new Map<string, IViewState>(),
|
||||
) {
|
||||
super();
|
||||
const viewDescriptorCollection = this._register(new ViewDescriptorCollection(container, contextKeyService));
|
||||
const viewDescriptorCollection = viewsService.getViewDescriptors(container);
|
||||
|
||||
this._register(viewDescriptorCollection.onDidChange(() => this.onDidChangeViewDescriptors(viewDescriptorCollection.viewDescriptors)));
|
||||
this.onDidChangeViewDescriptors(viewDescriptorCollection.viewDescriptors);
|
||||
this._register(viewDescriptorCollection.onDidChangeActiveViews(() => this.onDidChangeViewDescriptors(viewDescriptorCollection.activeViewDescriptors)));
|
||||
this.onDidChangeViewDescriptors(viewDescriptorCollection.activeViewDescriptors);
|
||||
}
|
||||
|
||||
isVisible(id: string): boolean {
|
||||
@@ -407,14 +417,14 @@ export class PersistentContributableViewsModel extends ContributableViewsModel {
|
||||
constructor(
|
||||
container: ViewContainer,
|
||||
viewletStateStorageId: string,
|
||||
@IContextKeyService contextKeyService: IContextKeyService,
|
||||
@IViewsService viewsService: IViewsService,
|
||||
@IStorageService storageService: IStorageService,
|
||||
@IWorkspaceContextService contextService: IWorkspaceContextService
|
||||
) {
|
||||
const hiddenViewsStorageId = `${viewletStateStorageId}.hidden`;
|
||||
const viewStates = PersistentContributableViewsModel.loadViewsStates(viewletStateStorageId, hiddenViewsStorageId, storageService, contextService);
|
||||
|
||||
super(container, contextKeyService, viewStates);
|
||||
super(container, viewsService, viewStates);
|
||||
|
||||
this.viewletStateStorageId = viewletStateStorageId;
|
||||
this.hiddenViewsStorageId = hiddenViewsStorageId;
|
||||
@@ -423,17 +433,26 @@ export class PersistentContributableViewsModel extends ContributableViewsModel {
|
||||
|
||||
this._register(this.onDidAdd(viewDescriptorRefs => this.saveVisibilityStates(viewDescriptorRefs.map(r => r.viewDescriptor))));
|
||||
this._register(this.onDidRemove(viewDescriptorRefs => this.saveVisibilityStates(viewDescriptorRefs.map(r => r.viewDescriptor))));
|
||||
this._register(this.storageService.onWillSaveState(() => this.saveViewsStates()));
|
||||
}
|
||||
|
||||
saveViewsStates(): void {
|
||||
private saveViewsStates(): void {
|
||||
const storedViewsStates: { [id: string]: { collapsed: boolean, size: number, order: number } } = {};
|
||||
|
||||
let hasState = false;
|
||||
for (const viewDescriptor of this.viewDescriptors) {
|
||||
const viewState = this.viewStates.get(viewDescriptor.id);
|
||||
if (viewState) {
|
||||
storedViewsStates[viewDescriptor.id] = { collapsed: viewState.collapsed, size: viewState.size, order: viewState.order };
|
||||
hasState = true;
|
||||
}
|
||||
}
|
||||
this.storageService.store(this.viewletStateStorageId, JSON.stringify(storedViewsStates), this.contextService.getWorkbenchState() !== WorkbenchState.EMPTY ? StorageScope.WORKSPACE : StorageScope.GLOBAL);
|
||||
|
||||
if (hasState) {
|
||||
this.storageService.store(this.viewletStateStorageId, JSON.stringify(storedViewsStates), StorageScope.WORKSPACE);
|
||||
} else {
|
||||
this.storageService.remove(this.viewletStateStorageId, StorageScope.WORKSPACE);
|
||||
}
|
||||
}
|
||||
|
||||
private saveVisibilityStates(viewDescriptors: IViewDescriptor[]): void {
|
||||
@@ -441,17 +460,17 @@ export class PersistentContributableViewsModel extends ContributableViewsModel {
|
||||
for (const viewDescriptor of viewDescriptors) {
|
||||
if (viewDescriptor.canToggleVisibility) {
|
||||
const viewState = this.viewStates.get(viewDescriptor.id);
|
||||
storedViewsVisibilityStates.push({ id: viewDescriptor.id, isHidden: viewState ? !viewState.visible : void 0 });
|
||||
storedViewsVisibilityStates.set(viewDescriptor.id, { id: viewDescriptor.id, isHidden: viewState ? !viewState.visible : void 0 });
|
||||
}
|
||||
}
|
||||
this.storageService.store(this.hiddenViewsStorageId, JSON.stringify(storedViewsVisibilityStates), StorageScope.GLOBAL);
|
||||
this.storageService.store(this.hiddenViewsStorageId, JSON.stringify(values(storedViewsVisibilityStates)), StorageScope.GLOBAL);
|
||||
}
|
||||
|
||||
private static loadViewsStates(viewletStateStorageId: string, hiddenViewsStorageId: string, storageService: IStorageService, contextService: IWorkspaceContextService): Map<string, IViewState> {
|
||||
const viewStates = new Map<string, IViewState>();
|
||||
const storedViewsStates = JSON.parse(storageService.get(viewletStateStorageId, contextService.getWorkbenchState() !== WorkbenchState.EMPTY ? StorageScope.WORKSPACE : StorageScope.GLOBAL, '{}'));
|
||||
const storedViewsStates = JSON.parse(storageService.get(viewletStateStorageId, StorageScope.WORKSPACE, '{}'));
|
||||
const viewsVisibilityStates = PersistentContributableViewsModel.loadViewsVisibilityState(hiddenViewsStorageId, storageService, contextService);
|
||||
for (const { id, isHidden } of viewsVisibilityStates) {
|
||||
for (const { id, isHidden } of values(viewsVisibilityStates)) {
|
||||
const viewState = storedViewsStates[id];
|
||||
if (viewState) {
|
||||
viewStates.set(id, <IViewState>{ ...viewState, ...{ visible: !isHidden } });
|
||||
@@ -468,43 +487,62 @@ export class PersistentContributableViewsModel extends ContributableViewsModel {
|
||||
return viewStates;
|
||||
}
|
||||
|
||||
private static loadViewsVisibilityState(hiddenViewsStorageId: string, storageService: IStorageService, contextService: IWorkspaceContextService): { id: string, isHidden: boolean }[] {
|
||||
private static loadViewsVisibilityState(hiddenViewsStorageId: string, storageService: IStorageService, contextService: IWorkspaceContextService): Map<string, { id: string, isHidden: boolean }> {
|
||||
const storedVisibilityStates = <Array<string | { id: string, isHidden: boolean }>>JSON.parse(storageService.get(hiddenViewsStorageId, StorageScope.GLOBAL, '[]'));
|
||||
return <{ id: string, isHidden: boolean }[]>storedVisibilityStates.map(c => typeof c === 'string' /* migration */ ? { id: c, isHidden: true } : c);
|
||||
}
|
||||
let hasDuplicates = false;
|
||||
const storedViewsVisibilityStates = storedVisibilityStates.reduce((result, storedState) => {
|
||||
if (typeof storedState === 'string' /* migration */) {
|
||||
hasDuplicates = hasDuplicates || result.has(storedState);
|
||||
result.set(storedState, { id: storedState, isHidden: true });
|
||||
} else {
|
||||
hasDuplicates = hasDuplicates || result.has(storedState.id);
|
||||
result.set(storedState.id, storedState);
|
||||
}
|
||||
return result;
|
||||
}, new Map<string, { id: string, isHidden: boolean }>());
|
||||
|
||||
dispose(): void {
|
||||
this.saveViewsStates();
|
||||
super.dispose();
|
||||
if (hasDuplicates) {
|
||||
storageService.store(hiddenViewsStorageId, JSON.stringify(values(storedViewsVisibilityStates)), StorageScope.GLOBAL);
|
||||
}
|
||||
|
||||
return storedViewsVisibilityStates;
|
||||
}
|
||||
}
|
||||
|
||||
const SCM_VIEWLET_ID = 'workbench.view.scm';
|
||||
|
||||
export class ViewsService extends Disposable implements IViewsService {
|
||||
|
||||
_serviceBrand: any;
|
||||
|
||||
private readonly viewDescriptorCollections: Map<ViewContainer, IViewDescriptorCollection>;
|
||||
private readonly activeViewContextKeys: Map<string, IContextKey<boolean>>;
|
||||
|
||||
constructor(
|
||||
@IInstantiationService private instantiationService: IInstantiationService,
|
||||
@ILifecycleService private lifecycleService: ILifecycleService,
|
||||
@IViewletService private viewletService: IViewletService,
|
||||
@IStorageService private storageService: IStorageService
|
||||
@IContextKeyService private contextKeyService: IContextKeyService
|
||||
) {
|
||||
super();
|
||||
|
||||
this.viewDescriptorCollections = new Map<ViewContainer, IViewDescriptorCollection>();
|
||||
this.activeViewContextKeys = new Map<string, IContextKey<boolean>>();
|
||||
|
||||
this.onDidRegisterViews(ViewsRegistry.getAllViews());
|
||||
this._register(ViewsRegistry.onViewsRegistered(views => this.onDidRegisterViews(views)));
|
||||
|
||||
const viewContainersRegistry = Registry.as<IViewContainersRegistry>(ViewContainerExtensions.ViewContainersRegistry);
|
||||
viewContainersRegistry.all.forEach(viewContainer => this.onDidRegisterViewContainer(viewContainer));
|
||||
this._register(viewContainersRegistry.onDidRegister(viewContainer => this.onDidRegisterViewContainer(viewContainer)));
|
||||
this._register(Registry.as<ViewletRegistry>(ViewletExtensions.Viewlets).onDidRegister(viewlet => this.viewletService.setViewletEnablement(viewlet.id, this.storageService.getBoolean(`viewservice.${viewlet.id}.enablement`, StorageScope.GLOBAL, viewlet.id !== TEST_VIEW_CONTAINER_ID))));
|
||||
}
|
||||
|
||||
openView(id: string, focus: boolean): TPromise<IView> {
|
||||
getViewDescriptors(container: ViewContainer): IViewDescriptorCollection {
|
||||
return this.viewDescriptorCollections.get(container);
|
||||
}
|
||||
|
||||
openView(id: string, focus: boolean): Thenable<IView> {
|
||||
const viewDescriptor = ViewsRegistry.getView(id);
|
||||
if (viewDescriptor) {
|
||||
const viewletDescriptor = this.viewletService.getViewlet(viewDescriptor.container.id);
|
||||
if (viewletDescriptor) {
|
||||
return this.viewletService.openViewlet(viewletDescriptor.id)
|
||||
return this.viewletService.openViewlet(viewletDescriptor.id, focus)
|
||||
.then((viewlet: IViewsViewlet) => {
|
||||
if (viewlet && viewlet.openView) {
|
||||
return viewlet.openView(id, focus);
|
||||
@@ -513,21 +551,62 @@ export class ViewsService extends Disposable implements IViewsService {
|
||||
});
|
||||
}
|
||||
}
|
||||
return TPromise.as(null);
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
|
||||
private onDidRegisterViewContainer(viewContainer: ViewContainer): void {
|
||||
// TODO: @Joao Remove this after moving SCM Viewlet to ViewContainerViewlet - https://github.com/Microsoft/vscode/issues/49054
|
||||
if (viewContainer.id !== SCM_VIEWLET_ID) {
|
||||
const viewDescriptorCollection = this._register(this.instantiationService.createInstance(ViewDescriptorCollection, viewContainer));
|
||||
this._register(viewDescriptorCollection.onDidChange(() => this.updateViewletEnablement(viewContainer, viewDescriptorCollection)));
|
||||
this.lifecycleService.when(LifecyclePhase.Eventually).then(() => this.updateViewletEnablement(viewContainer, viewDescriptorCollection));
|
||||
const viewDescriptorCollection = this._register(new ViewDescriptorCollection(viewContainer, this.contextKeyService));
|
||||
|
||||
this.onDidChangeActiveViews({ added: viewDescriptorCollection.activeViewDescriptors, removed: [] });
|
||||
this._register(viewDescriptorCollection.onDidChangeActiveViews(changed => this.onDidChangeActiveViews(changed)));
|
||||
|
||||
this.viewDescriptorCollections.set(viewContainer, viewDescriptorCollection);
|
||||
}
|
||||
|
||||
private onDidChangeActiveViews({ added, removed }: { added: IViewDescriptor[], removed: IViewDescriptor[] }): void {
|
||||
added.forEach(viewDescriptor => this.getOrCreateActiveViewContextKey(viewDescriptor).set(true));
|
||||
removed.forEach(viewDescriptor => this.getOrCreateActiveViewContextKey(viewDescriptor).set(false));
|
||||
}
|
||||
|
||||
private onDidRegisterViews(viewDescriptors: IViewDescriptor[]): void {
|
||||
for (const viewDescriptor of viewDescriptors) {
|
||||
const viewlet = this.viewletService.getViewlet(viewDescriptor.container.id);
|
||||
const command: ICommandAction = {
|
||||
id: viewDescriptor.focusCommand ? viewDescriptor.focusCommand.id : `${viewDescriptor.id}.focus`,
|
||||
title: { original: `Focus on ${viewDescriptor.name} View`, value: localize('focus view', "Focus on {0} View", viewDescriptor.name) },
|
||||
category: viewlet ? viewlet.name : localize('view category', "View"),
|
||||
};
|
||||
const when = ContextKeyExpr.has(`${viewDescriptor.id}.active`);
|
||||
|
||||
CommandsRegistry.registerCommand(command.id, () => this.openView(viewDescriptor.id, true).then(() => null));
|
||||
|
||||
MenuRegistry.appendMenuItem(MenuId.CommandPalette, {
|
||||
command,
|
||||
when
|
||||
});
|
||||
|
||||
if (viewDescriptor.focusCommand && viewDescriptor.focusCommand.keybindings) {
|
||||
KeybindingsRegistry.registerKeybindingRule({
|
||||
id: command.id,
|
||||
when,
|
||||
weight: KeybindingWeight.WorkbenchContrib,
|
||||
primary: viewDescriptor.focusCommand.keybindings.primary,
|
||||
secondary: viewDescriptor.focusCommand.keybindings.secondary,
|
||||
linux: viewDescriptor.focusCommand.keybindings.linux,
|
||||
mac: viewDescriptor.focusCommand.keybindings.mac,
|
||||
win: viewDescriptor.focusCommand.keybindings.win
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private updateViewletEnablement(viewContainer: ViewContainer, viewDescriptorCollection: ViewDescriptorCollection): void {
|
||||
const enabled = viewDescriptorCollection.viewDescriptors.length > 0;
|
||||
this.viewletService.setViewletEnablement(viewContainer.id, enabled);
|
||||
this.storageService.store(`viewservice.${viewContainer.id}.enablement`, enabled, StorageScope.GLOBAL);
|
||||
private getOrCreateActiveViewContextKey(viewDescriptor: IViewDescriptor): IContextKey<boolean> {
|
||||
const activeContextKeyId = `${viewDescriptor.id}.active`;
|
||||
let contextKey = this.activeViewContextKeys.get(activeContextKeyId);
|
||||
if (!contextKey) {
|
||||
contextKey = new RawContextKey(activeContextKeyId, false).bindTo(this.contextKeyService);
|
||||
this.activeViewContextKeys.set(activeContextKeyId, contextKey);
|
||||
}
|
||||
return contextKey;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user