Merge from master

This commit is contained in:
Raj Musuku
2019-02-21 17:56:04 -08:00
parent 5a146e34fa
commit 666ae11639
11482 changed files with 119352 additions and 255574 deletions

View File

@@ -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;