mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-03-23 05:10:30 -04:00
Merge from master
This commit is contained in:
@@ -3,17 +3,12 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import 'vs/css!./media/compositepart';
|
||||
import * as nls from 'vs/nls';
|
||||
import { defaultGenerator } from 'vs/base/common/idGenerator';
|
||||
import { TPromise } from 'vs/base/common/winjs.base';
|
||||
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
|
||||
import { Builder, $ } from 'vs/base/browser/builder';
|
||||
import * as strings from 'vs/base/common/strings';
|
||||
import { Emitter } from 'vs/base/common/event';
|
||||
import * as types from 'vs/base/common/types';
|
||||
import * as errors from 'vs/base/common/errors';
|
||||
import { ToolBar } from 'vs/base/browser/ui/toolbar/toolbar';
|
||||
import { IActionItem, ActionsOrientation } from 'vs/base/browser/ui/actionbar/actionbar';
|
||||
@@ -35,7 +30,8 @@ import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
||||
import { IThemeService } from 'vs/platform/theme/common/themeService';
|
||||
import { attachProgressBarStyler } from 'vs/platform/theme/common/styler';
|
||||
import { INotificationService } from 'vs/platform/notification/common/notification';
|
||||
import { Dimension } from 'vs/base/browser/dom';
|
||||
import { Dimension, append, $, addClass, hide, show, addClasses } from 'vs/base/browser/dom';
|
||||
import { AnchorAlignment } from 'vs/base/browser/ui/contextview/contextview';
|
||||
|
||||
export interface ICompositeTitleLabel {
|
||||
|
||||
@@ -52,13 +48,13 @@ export interface ICompositeTitleLabel {
|
||||
|
||||
export abstract class CompositePart<T extends Composite> extends Part {
|
||||
|
||||
protected _onDidCompositeOpen = this._register(new Emitter<IComposite>());
|
||||
protected _onDidCompositeOpen = this._register(new Emitter<{ composite: IComposite, focus: boolean }>());
|
||||
protected _onDidCompositeClose = this._register(new Emitter<IComposite>());
|
||||
|
||||
protected toolBar: ToolBar;
|
||||
|
||||
private instantiatedCompositeListeners: IDisposable[];
|
||||
private mapCompositeToCompositeContainer: { [compositeId: string]: Builder; };
|
||||
private mapCompositeToCompositeContainer: { [compositeId: string]: HTMLElement; };
|
||||
private mapActionsBindingToComposite: { [compositeId: string]: () => void; };
|
||||
private mapProgressServiceToComposite: { [compositeId: string]: IProgressService; };
|
||||
private activeComposite: Composite;
|
||||
@@ -88,7 +84,7 @@ export abstract class CompositePart<T extends Composite> extends Part {
|
||||
id: string,
|
||||
options: IPartOptions
|
||||
) {
|
||||
super(id, options, themeService);
|
||||
super(id, options, themeService, storageService);
|
||||
|
||||
this.instantiatedCompositeListeners = [];
|
||||
this.mapCompositeToCompositeContainer = {};
|
||||
@@ -99,7 +95,7 @@ export abstract class CompositePart<T extends Composite> extends Part {
|
||||
this.lastActiveCompositeId = storageService.get(activeCompositeSettingsKey, StorageScope.WORKSPACE, this.defaultCompositeId);
|
||||
}
|
||||
|
||||
protected openComposite(id: string, focus?: boolean): TPromise<Composite> {
|
||||
protected openComposite(id: string, focus?: boolean): Composite {
|
||||
// Check if composite already visible and just focus in that case
|
||||
if (this.activeComposite && this.activeComposite.getId() === id) {
|
||||
if (focus) {
|
||||
@@ -107,66 +103,57 @@ export abstract class CompositePart<T extends Composite> extends Part {
|
||||
}
|
||||
|
||||
// Fullfill promise with composite that is being opened
|
||||
return TPromise.as(this.activeComposite);
|
||||
return this.activeComposite;
|
||||
}
|
||||
|
||||
// Open
|
||||
return this.doOpenComposite(id, focus);
|
||||
}
|
||||
|
||||
private doOpenComposite(id: string, focus?: boolean): TPromise<Composite> {
|
||||
private doOpenComposite(id: string, focus?: boolean): Composite {
|
||||
|
||||
// Use a generated token to avoid race conditions from long running promises
|
||||
const currentCompositeOpenToken = defaultGenerator.nextId();
|
||||
this.currentCompositeOpenToken = currentCompositeOpenToken;
|
||||
|
||||
// Hide current
|
||||
let hidePromise: TPromise<Composite>;
|
||||
if (this.activeComposite) {
|
||||
hidePromise = this.hideActiveComposite();
|
||||
} else {
|
||||
hidePromise = TPromise.as(null);
|
||||
this.hideActiveComposite();
|
||||
}
|
||||
|
||||
return hidePromise.then(() => {
|
||||
// Update Title
|
||||
this.updateTitle(id);
|
||||
|
||||
// Update Title
|
||||
this.updateTitle(id);
|
||||
// Create composite
|
||||
const composite = this.createComposite(id, true);
|
||||
|
||||
// Create composite
|
||||
const composite = this.createComposite(id, true);
|
||||
// Check if another composite opened meanwhile and return in that case
|
||||
if ((this.currentCompositeOpenToken !== currentCompositeOpenToken) || (this.activeComposite && this.activeComposite.getId() !== composite.getId())) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// Check if another composite opened meanwhile and return in that case
|
||||
if ((this.currentCompositeOpenToken !== currentCompositeOpenToken) || (this.activeComposite && this.activeComposite.getId() !== composite.getId())) {
|
||||
return TPromise.as(null);
|
||||
}
|
||||
|
||||
// Check if composite already visible and just focus in that case
|
||||
if (this.activeComposite && this.activeComposite.getId() === composite.getId()) {
|
||||
if (focus) {
|
||||
composite.focus();
|
||||
}
|
||||
|
||||
// Fullfill promise with composite that is being opened
|
||||
return TPromise.as(composite);
|
||||
}
|
||||
|
||||
// Show Composite and Focus
|
||||
return this.showComposite(composite).then(() => {
|
||||
if (focus) {
|
||||
composite.focus();
|
||||
}
|
||||
|
||||
// Fullfill promise with composite that is being opened
|
||||
return composite;
|
||||
});
|
||||
}).then(composite => {
|
||||
if (composite) {
|
||||
this._onDidCompositeOpen.fire(composite);
|
||||
// Check if composite already visible and just focus in that case
|
||||
if (this.activeComposite && this.activeComposite.getId() === composite.getId()) {
|
||||
if (focus) {
|
||||
composite.focus();
|
||||
}
|
||||
|
||||
this._onDidCompositeOpen.fire({ composite, focus });
|
||||
return composite;
|
||||
});
|
||||
}
|
||||
|
||||
// Show Composite and Focus
|
||||
this.showComposite(composite);
|
||||
if (focus) {
|
||||
composite.focus();
|
||||
}
|
||||
|
||||
// Return with the composite that is being opened
|
||||
if (composite) {
|
||||
this._onDidCompositeOpen.fire({ composite, focus });
|
||||
}
|
||||
|
||||
return composite;
|
||||
}
|
||||
|
||||
protected createComposite(id: string, isActive?: boolean): Composite {
|
||||
@@ -199,7 +186,7 @@ export abstract class CompositePart<T extends Composite> extends Part {
|
||||
throw new Error(strings.format('Unable to find composite with id {0}', id));
|
||||
}
|
||||
|
||||
protected showComposite(composite: Composite): TPromise<void> {
|
||||
protected showComposite(composite: Composite): void {
|
||||
|
||||
// Remember Composite
|
||||
this.activeComposite = composite;
|
||||
@@ -215,105 +202,92 @@ export abstract class CompositePart<T extends Composite> extends Part {
|
||||
// Remember
|
||||
this.lastActiveCompositeId = this.activeComposite.getId();
|
||||
|
||||
let createCompositePromise: TPromise<void>;
|
||||
|
||||
// Composites created for the first time
|
||||
let compositeContainer = this.mapCompositeToCompositeContainer[composite.getId()];
|
||||
if (!compositeContainer) {
|
||||
|
||||
// Build Container off-DOM
|
||||
compositeContainer = $().div({
|
||||
'class': ['composite', this.compositeCSSClass],
|
||||
id: composite.getId()
|
||||
}, div => {
|
||||
createCompositePromise = composite.create(div.getHTMLElement()).then(() => {
|
||||
composite.updateStyles();
|
||||
});
|
||||
});
|
||||
compositeContainer = $('.composite');
|
||||
addClasses(compositeContainer, this.compositeCSSClass);
|
||||
compositeContainer.id = composite.getId();
|
||||
|
||||
composite.create(compositeContainer);
|
||||
composite.updateStyles();
|
||||
|
||||
// Remember composite container
|
||||
this.mapCompositeToCompositeContainer[composite.getId()] = compositeContainer;
|
||||
}
|
||||
|
||||
// Composite already exists but is hidden
|
||||
else {
|
||||
createCompositePromise = TPromise.as(null);
|
||||
}
|
||||
|
||||
// Report progress for slow loading composites (but only if we did not create the composites before already)
|
||||
const progressService = this.mapProgressServiceToComposite[composite.getId()];
|
||||
if (progressService && !compositeContainer) {
|
||||
this.mapProgressServiceToComposite[composite.getId()].showWhile(createCompositePromise, this.partService.isCreated() ? 800 : 3200 /* less ugly initial startup */);
|
||||
this.mapProgressServiceToComposite[composite.getId()].showWhile(Promise.resolve(), this.partService.isRestored() ? 800 : 3200 /* less ugly initial startup */);
|
||||
}
|
||||
|
||||
// Fill Content and Actions
|
||||
return createCompositePromise.then(() => {
|
||||
// Make sure that the user meanwhile did not open another composite or closed the part containing the composite
|
||||
if (!this.activeComposite || composite.getId() !== this.activeComposite.getId()) {
|
||||
return void 0;
|
||||
}
|
||||
|
||||
// Make sure that the user meanwhile did not open another composite or closed the part containing the composite
|
||||
if (!this.activeComposite || composite.getId() !== this.activeComposite.getId()) {
|
||||
return void 0;
|
||||
// Take Composite on-DOM and show
|
||||
this.getContentArea().appendChild(compositeContainer);
|
||||
show(compositeContainer);
|
||||
|
||||
// Setup action runner
|
||||
this.toolBar.actionRunner = composite.getActionRunner();
|
||||
|
||||
// Update title with composite title if it differs from descriptor
|
||||
const descriptor = this.registry.getComposite(composite.getId());
|
||||
if (descriptor && descriptor.name !== composite.getTitle()) {
|
||||
this.updateTitle(composite.getId(), composite.getTitle());
|
||||
}
|
||||
|
||||
// Handle Composite Actions
|
||||
let actionsBinding = this.mapActionsBindingToComposite[composite.getId()];
|
||||
if (!actionsBinding) {
|
||||
actionsBinding = this.collectCompositeActions(composite);
|
||||
this.mapActionsBindingToComposite[composite.getId()] = actionsBinding;
|
||||
}
|
||||
actionsBinding();
|
||||
|
||||
if (this.telemetryActionsListener) {
|
||||
this.telemetryActionsListener.dispose();
|
||||
this.telemetryActionsListener = null;
|
||||
}
|
||||
|
||||
// Action Run Handling
|
||||
this.telemetryActionsListener = this.toolBar.actionRunner.onDidRun(e => {
|
||||
|
||||
// Check for Error
|
||||
if (e.error && !errors.isPromiseCanceledError(e.error)) {
|
||||
this.notificationService.error(e.error);
|
||||
}
|
||||
|
||||
// Take Composite on-DOM and show
|
||||
compositeContainer.build(this.getContentArea());
|
||||
compositeContainer.show();
|
||||
|
||||
// Setup action runner
|
||||
this.toolBar.actionRunner = composite.getActionRunner();
|
||||
|
||||
// Update title with composite title if it differs from descriptor
|
||||
const descriptor = this.registry.getComposite(composite.getId());
|
||||
if (descriptor && descriptor.name !== composite.getTitle()) {
|
||||
this.updateTitle(composite.getId(), composite.getTitle());
|
||||
// Log in telemetry
|
||||
if (this.telemetryService) {
|
||||
/* __GDPR__
|
||||
"workbenchActionExecuted" : {
|
||||
"id" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
|
||||
"from": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }
|
||||
}
|
||||
*/
|
||||
this.telemetryService.publicLog('workbenchActionExecuted', { id: e.action.id, from: this.nameForTelemetry });
|
||||
}
|
||||
});
|
||||
|
||||
// Handle Composite Actions
|
||||
let actionsBinding = this.mapActionsBindingToComposite[composite.getId()];
|
||||
if (!actionsBinding) {
|
||||
actionsBinding = this.collectCompositeActions(composite);
|
||||
this.mapActionsBindingToComposite[composite.getId()] = actionsBinding;
|
||||
}
|
||||
actionsBinding();
|
||||
// Indicate to composite that it is now visible
|
||||
composite.setVisible(true);
|
||||
|
||||
if (this.telemetryActionsListener) {
|
||||
this.telemetryActionsListener.dispose();
|
||||
this.telemetryActionsListener = null;
|
||||
}
|
||||
// Make sure that the user meanwhile did not open another composite or closed the part containing the composite
|
||||
if (!this.activeComposite || composite.getId() !== this.activeComposite.getId()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Action Run Handling
|
||||
this.telemetryActionsListener = this.toolBar.actionRunner.onDidRun(e => {
|
||||
|
||||
// Check for Error
|
||||
if (e.error && !errors.isPromiseCanceledError(e.error)) {
|
||||
this.notificationService.error(e.error);
|
||||
}
|
||||
|
||||
// Log in telemetry
|
||||
if (this.telemetryService) {
|
||||
/* __GDPR__
|
||||
"workbenchActionExecuted" : {
|
||||
"id" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
|
||||
"from": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }
|
||||
}
|
||||
*/
|
||||
this.telemetryService.publicLog('workbenchActionExecuted', { id: e.action.id, from: this.nameForTelemetry });
|
||||
}
|
||||
});
|
||||
|
||||
// Indicate to composite that it is now visible
|
||||
return composite.setVisible(true).then(() => {
|
||||
|
||||
// Make sure that the user meanwhile did not open another composite or closed the part containing the composite
|
||||
if (!this.activeComposite || composite.getId() !== this.activeComposite.getId()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Make sure the composite is layed out
|
||||
if (this.contentAreaSize) {
|
||||
composite.layout(this.contentAreaSize);
|
||||
}
|
||||
});
|
||||
}, error => this.onError(error));
|
||||
// Make sure the composite is layed out
|
||||
if (this.contentAreaSize) {
|
||||
composite.layout(this.contentAreaSize);
|
||||
}
|
||||
}
|
||||
|
||||
protected onTitleAreaUpdate(compositeId: string): void {
|
||||
@@ -375,9 +349,9 @@ export abstract class CompositePart<T extends Composite> extends Part {
|
||||
return this.lastActiveCompositeId;
|
||||
}
|
||||
|
||||
protected hideActiveComposite(): TPromise<Composite> {
|
||||
protected hideActiveComposite(): Composite {
|
||||
if (!this.activeComposite) {
|
||||
return TPromise.as(null); // Nothing to do
|
||||
return undefined; // Nothing to do
|
||||
}
|
||||
|
||||
const composite = this.activeComposite;
|
||||
@@ -386,65 +360,58 @@ export abstract class CompositePart<T extends Composite> extends Part {
|
||||
const compositeContainer = this.mapCompositeToCompositeContainer[composite.getId()];
|
||||
|
||||
// Indicate to Composite
|
||||
return composite.setVisible(false).then(() => {
|
||||
composite.setVisible(false);
|
||||
|
||||
// Take Container Off-DOM and hide
|
||||
compositeContainer.offDOM();
|
||||
compositeContainer.hide();
|
||||
// Take Container Off-DOM and hide
|
||||
compositeContainer.remove();
|
||||
hide(compositeContainer);
|
||||
|
||||
// Clear any running Progress
|
||||
this.progressBar.stop().hide();
|
||||
// Clear any running Progress
|
||||
this.progressBar.stop().hide();
|
||||
|
||||
// Empty Actions
|
||||
this.toolBar.setActions([])();
|
||||
this._onDidCompositeClose.fire(composite);
|
||||
// Empty Actions
|
||||
this.toolBar.setActions([])();
|
||||
this._onDidCompositeClose.fire(composite);
|
||||
|
||||
return composite;
|
||||
});
|
||||
return composite;
|
||||
}
|
||||
|
||||
createTitleArea(parent: HTMLElement): HTMLElement {
|
||||
|
||||
// Title Area Container
|
||||
const titleArea = $(parent).div({
|
||||
'class': ['composite', 'title']
|
||||
});
|
||||
const titleArea = append(parent, $('.composite'));
|
||||
addClass(titleArea, 'title');
|
||||
|
||||
// Left Title Label
|
||||
this.titleLabel = this.createTitleLabel(titleArea.getHTMLElement());
|
||||
this.titleLabel = this.createTitleLabel(titleArea);
|
||||
|
||||
// Right Actions Container
|
||||
$(titleArea).div({
|
||||
'class': 'title-actions'
|
||||
}, div => {
|
||||
const titleActionsContainer = append(titleArea, $('.title-actions'));
|
||||
|
||||
// Toolbar
|
||||
this.toolBar = this._register(new ToolBar(div.getHTMLElement(), this.contextMenuService, {
|
||||
actionItemProvider: action => this.actionItemProvider(action as Action),
|
||||
orientation: ActionsOrientation.HORIZONTAL,
|
||||
getKeyBinding: action => this.keybindingService.lookupKeybinding(action.id)
|
||||
}));
|
||||
});
|
||||
// Toolbar
|
||||
this.toolBar = this._register(new ToolBar(titleActionsContainer, this.contextMenuService, {
|
||||
actionItemProvider: action => this.actionItemProvider(action as Action),
|
||||
orientation: ActionsOrientation.HORIZONTAL,
|
||||
getKeyBinding: action => this.keybindingService.lookupKeybinding(action.id),
|
||||
anchorAlignmentProvider: () => this.getTitleAreaDropDownAnchorAlignment()
|
||||
}));
|
||||
|
||||
return titleArea.getHTMLElement();
|
||||
return titleArea;
|
||||
}
|
||||
|
||||
protected createTitleLabel(parent: HTMLElement): ICompositeTitleLabel {
|
||||
let titleLabel: Builder;
|
||||
$(parent).div({
|
||||
'class': 'title-label'
|
||||
}, div => {
|
||||
titleLabel = div.element('h2');
|
||||
});
|
||||
const titleContainer = append(parent, $('.title-label'));
|
||||
const titleLabel = append(titleContainer, $('h2'));
|
||||
|
||||
const $this = this;
|
||||
return {
|
||||
updateTitle: (id, title, keybinding) => {
|
||||
titleLabel.safeInnerHtml(title);
|
||||
titleLabel.title(keybinding ? nls.localize('titleTooltip', "{0} ({1})", title, keybinding) : title);
|
||||
titleLabel.innerHTML = strings.escape(title);
|
||||
titleLabel.title = keybinding ? nls.localize('titleTooltip', "{0} ({1})", title, keybinding) : title;
|
||||
},
|
||||
|
||||
updateStyles: () => {
|
||||
titleLabel.style('color', $this.getColor($this.titleForegroundColor));
|
||||
titleLabel.style.color = $this.getColor($this.titleForegroundColor);
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -467,17 +434,13 @@ export abstract class CompositePart<T extends Composite> extends Part {
|
||||
}
|
||||
|
||||
createContentArea(parent: HTMLElement): HTMLElement {
|
||||
return $(parent).div({
|
||||
'class': 'content'
|
||||
}, div => {
|
||||
this.progressBar = this._register(new ProgressBar(div.getHTMLElement()));
|
||||
this._register(attachProgressBarStyler(this.progressBar, this.themeService));
|
||||
this.progressBar.hide();
|
||||
}).getHTMLElement();
|
||||
}
|
||||
const contentContainer = append(parent, $('.content'));
|
||||
|
||||
private onError(error: any): void {
|
||||
this.notificationService.error(types.isString(error) ? new Error(error) : error);
|
||||
this.progressBar = this._register(new ProgressBar(contentContainer));
|
||||
this._register(attachProgressBarStyler(this.progressBar, this.themeService));
|
||||
this.progressBar.hide();
|
||||
|
||||
return contentContainer;
|
||||
}
|
||||
|
||||
getProgressIndicator(id: string): IProgressService {
|
||||
@@ -492,6 +455,10 @@ export abstract class CompositePart<T extends Composite> extends Part {
|
||||
return [];
|
||||
}
|
||||
|
||||
protected getTitleAreaDropDownAnchorAlignment(): AnchorAlignment {
|
||||
return AnchorAlignment.RIGHT;
|
||||
}
|
||||
|
||||
layout(dimension: Dimension): Dimension[] {
|
||||
|
||||
// Pass to super
|
||||
@@ -506,12 +473,6 @@ export abstract class CompositePart<T extends Composite> extends Part {
|
||||
return sizes;
|
||||
}
|
||||
|
||||
shutdown(): void {
|
||||
this.instantiatedComposites.forEach(i => i.shutdown());
|
||||
|
||||
super.shutdown();
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
this.mapCompositeToCompositeContainer = null;
|
||||
this.mapProgressServiceToComposite = null;
|
||||
|
||||
Reference in New Issue
Block a user