Merge from vscode 27ada910e121e23a6d95ecca9cae595fb98ab568

This commit is contained in:
ADS Merger
2020-04-30 00:53:43 +00:00
parent 87e5239713
commit 93f35ca321
413 changed files with 7190 additions and 8756 deletions

View File

@@ -10,7 +10,7 @@ import { ModelViewInput } from 'sql/workbench/browser/modelComponents/modelViewI
import { ModelViewEditor } from 'sql/workbench/browser/modelComponents/modelViewEditor';
// Model View editor registration
const viewModelEditorDescriptor = new EditorDescriptor(
const viewModelEditorDescriptor = EditorDescriptor.create(
ModelViewEditor,
ModelViewEditor.ID,
'ViewModel'

View File

@@ -3,73 +3,69 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import 'vs/css!./media/views';
import { Event, Emitter } from 'vs/base/common/event';
import { IDisposable, Disposable, toDisposable, DisposableStore, MutableDisposable } from 'vs/base/common/lifecycle';
import { IDisposable, Disposable, toDisposable } from 'vs/base/common/lifecycle';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { IAction, IActionViewItem, ActionRunner, Action } from 'vs/base/common/actions';
import { IAction, ActionRunner } from 'vs/base/common/actions';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
import { IMenuService, MenuId, MenuItemAction } from 'vs/platform/actions/common/actions';
import { ContextAwareMenuEntryActionViewItem, createAndFillInActionBarActions, createAndFillInContextMenuActions } from 'vs/platform/actions/browser/menuEntryActionViewItem';
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { TreeItemCollapsibleState, ITreeViewDataProvider, TreeViewItemHandleArg, ITreeViewDescriptor, IViewsRegistry, ViewContainer, ITreeItemLabel, Extensions, IViewDescriptorService } from 'vs/workbench/common/views';
import { IMenuService, MenuId, MenuItemAction, registerAction2, Action2 } from 'vs/platform/actions/common/actions';
import { ContextAwareMenuEntryActionViewItem, createAndFillInContextMenuActions } from 'vs/platform/actions/browser/menuEntryActionViewItem';
import { IContextKeyService, ContextKeyExpr, ContextKeyEqualsExpr, RawContextKey, IContextKey } from 'vs/platform/contextkey/common/contextkey';
import { TreeItemCollapsibleState, ITreeViewDataProvider, TreeViewItemHandleArg, ITreeViewDescriptor, IViewsRegistry, ITreeItemLabel, Extensions, IViewDescriptorService, ViewContainer, ViewContainerLocation } from 'vs/workbench/common/views';
import { IViewletViewOptions } from 'vs/workbench/browser/parts/views/viewsViewlet';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { INotificationService } from 'vs/platform/notification/common/notification';
import { IProgressService } from 'vs/platform/progress/common/progress';
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
import { IWorkbenchThemeService } from 'vs/workbench/services/themes/common/workbenchThemeService';
import { ICommandService } from 'vs/platform/commands/common/commands';
import * as DOM from 'vs/base/browser/dom';
import { ResourceLabels, IResourceLabel } from 'vs/workbench/browser/labels';
import { ActionBar, IActionViewItemProvider, ActionViewItem } from 'vs/base/browser/ui/actionbar/actionbar';
import { URI } from 'vs/base/common/uri';
import { dirname, basename } from 'vs/base/common/resources';
import { LIGHT, FileThemeIcon, FolderThemeIcon, registerThemingParticipant, IThemeService } from 'vs/platform/theme/common/themeService';
import { LIGHT, FileThemeIcon, FolderThemeIcon, registerThemingParticipant, ThemeIcon, IThemeService } from 'vs/platform/theme/common/themeService';
import { FileKind } from 'vs/platform/files/common/files';
import { WorkbenchAsyncDataTree, TreeResourceNavigator } from 'vs/platform/list/browser/listService';
import { ViewPane, IViewPaneOptions } from 'vs/workbench/browser/parts/views/viewPaneContainer';
import { localize } from 'vs/nls';
import { timeout } from 'vs/base/common/async';
import { editorFindMatchHighlight, editorFindMatchHighlightBorder, textLinkForeground, textCodeBlockBackground, focusBorder } from 'vs/platform/theme/common/colorRegistry';
import { IMarkdownString } from 'vs/base/common/htmlContent';
import { textLinkForeground, textCodeBlockBackground, focusBorder, listFilterMatchHighlight, listFilterMatchHighlightBorder } from 'vs/platform/theme/common/colorRegistry';
import { isString } from 'vs/base/common/types';
import { renderMarkdown, MarkdownRenderOptions } from 'vs/base/browser/markdownRenderer';
import { onUnexpectedError } from 'vs/base/common/errors';
import { IOpenerService } from 'vs/platform/opener/common/opener';
import { IMarkdownRenderResult } from 'vs/editor/contrib/markdown/markdownRenderer';
import { ILabelService } from 'vs/platform/label/common/label';
import { Registry } from 'vs/platform/registry/common/platform';
import { IListVirtualDelegate, IIdentityProvider } from 'vs/base/browser/ui/list/list';
import { ITreeRenderer, ITreeNode, IAsyncDataSource, ITreeContextMenuEvent } from 'vs/base/browser/ui/tree/tree';
import { FuzzyScore, createMatches } from 'vs/base/common/filters';
import { CollapseAllAction } from 'vs/base/browser/ui/tree/treeDefaults';
import { isFalsyOrWhitespace } from 'vs/base/common/strings';
import { SIDE_BAR_BACKGROUND, PANEL_BACKGROUND } from 'vs/workbench/common/theme';
import { IOpenerService } from 'vs/platform/opener/common/opener';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { firstIndex } from 'vs/base/common/arrays';
import { ITreeItem, ITreeView } from 'sql/workbench/common/views';
import { UserCancelledConnectionError } from 'sql/base/common/errors';
import { IOEShimService } from 'sql/workbench/services/objectExplorer/browser/objectExplorerViewTreeShim';
import { NodeContextKey } from 'sql/workbench/browser/parts/views/nodeContext';
import { UserCancelledConnectionError } from 'sql/base/common/errors';
import { firstIndex } from 'vs/base/common/arrays';
import { ViewPane, IViewPaneOptions } from 'vs/workbench/browser/parts/views/viewPaneContainer';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
export class CustomTreeViewPane extends ViewPane {
export class TreeViewPane extends ViewPane {
private treeView: ITreeView;
constructor(
options: IViewletViewOptions,
@INotificationService private readonly notificationService: INotificationService,
@IKeybindingService keybindingService: IKeybindingService,
@IContextMenuService contextMenuService: IContextMenuService,
@IConfigurationService configurationService: IConfigurationService,
@IContextKeyService contextKeyService: IContextKeyService,
@IInstantiationService instantiationService: IInstantiationService,
@IViewDescriptorService viewDescriptorService: IViewDescriptorService,
@IOpenerService protected openerService: IOpenerService,
@IThemeService protected themeService: IThemeService,
@IInstantiationService instantiationService: IInstantiationService,
@IOpenerService openerService: IOpenerService,
@IThemeService themeService: IThemeService,
@ITelemetryService telemetryService: ITelemetryService,
) {
super({ ...(options as IViewPaneOptions) }, keybindingService, contextMenuService, configurationService, contextKeyService, viewDescriptorService, instantiationService, openerService, themeService, telemetryService);
super({ ...(options as IViewPaneOptions), titleMenuId: MenuId.ViewTitle }, keybindingService, contextMenuService, configurationService, contextKeyService, viewDescriptorService, instantiationService, openerService, themeService, telemetryService);
const { treeView } = (<ITreeViewDescriptor>Registry.as<IViewsRegistry>(Extensions.ViewsRegistry).getView(options.id));
this.treeView = treeView as ITreeView;
this._register(this.treeView.onDidChangeActions(() => this.updateActions(), this));
@@ -86,23 +82,22 @@ export class CustomTreeViewPane extends ViewPane {
}
renderBody(container: HTMLElement): void {
if (this.treeView instanceof CustomTreeView) {
super.renderBody(container);
if (this.treeView instanceof TreeView) {
this.treeView.show(container);
}
}
shouldShowWelcome(): boolean {
return (this.treeView.dataProvider === undefined) && (this.treeView.message === undefined);
return ((this.treeView.dataProvider === undefined) || !!this.treeView.dataProvider.isTreeEmpty) && (this.treeView.message === undefined);
}
layoutBody(height: number, width: number): void {
super.layoutBody(height, width);
this.treeView.layout(height, width);
}
getActionViewItem(action: IAction): IActionViewItem | undefined {
return action instanceof MenuItemAction ? new ContextAwareMenuEntryActionViewItem(action, this.keybindingService, this.notificationService, this.contextMenuService) : undefined;
}
getOptimalWidth(): number {
return this.treeView.getOptimalWidth();
}
@@ -112,51 +107,6 @@ export class CustomTreeViewPane extends ViewPane {
}
}
class TitleMenus extends Disposable {
private titleActions: IAction[] = [];
private readonly titleActionsDisposable = this._register(new MutableDisposable());
private titleSecondaryActions: IAction[] = [];
private _onDidChangeTitle = this._register(new Emitter<void>());
readonly onDidChangeTitle: Event<void> = this._onDidChangeTitle.event;
constructor(
id: string,
@IContextKeyService private readonly contextKeyService: IContextKeyService,
@IMenuService private readonly menuService: IMenuService,
) {
super();
const scopedContextKeyService = this._register(this.contextKeyService.createScoped());
scopedContextKeyService.createKey('view', id);
const titleMenu = this._register(this.menuService.createMenu(MenuId.ViewTitle, scopedContextKeyService));
const updateActions = () => {
this.titleActions = [];
this.titleSecondaryActions = [];
this.titleActionsDisposable.value = createAndFillInActionBarActions(titleMenu, undefined, { primary: this.titleActions, secondary: this.titleSecondaryActions });
this._onDidChangeTitle.fire();
};
this._register(titleMenu.onDidChange(updateActions));
updateActions();
this._register(toDisposable(() => {
this.titleActions = [];
this.titleSecondaryActions = [];
}));
}
getTitleActions(): IAction[] {
return this.titleActions;
}
getTitleSecondaryActions(): IAction[] {
return this.titleSecondaryActions;
}
}
class Root implements ITreeItem {
label = { label: 'root' };
handle = '0';
@@ -167,29 +117,30 @@ class Root implements ITreeItem {
const noDataProviderMessage = localize('no-dataprovider', "There is no data provider registered that can provide view data.");
export class CustomTreeView extends Disposable implements ITreeView {
class Tree extends WorkbenchAsyncDataTree<ITreeItem, ITreeItem, FuzzyScore> { }
export class TreeView extends Disposable implements ITreeView {
private isVisible: boolean = false;
private activated: boolean = false;
private _hasIconForParentNode = false;
private _hasIconForLeafNode = false;
private _showCollapseAllAction = false;
private readonly collapseAllContextKey: RawContextKey<boolean>;
private readonly collapseAllContext: IContextKey<boolean>;
private readonly refreshContextKey: RawContextKey<boolean>;
private readonly refreshContext: IContextKey<boolean>;
private focused: boolean = false;
private domNode: HTMLElement;
private treeContainer: HTMLElement;
private _messageValue: string | IMarkdownString | undefined;
private domNode!: HTMLElement;
private treeContainer!: HTMLElement;
private _messageValue: string | undefined;
private _canSelectMany: boolean = false;
private messageElement: HTMLDivElement;
private tree: WorkbenchAsyncDataTree<ITreeItem, ITreeItem, FuzzyScore>;
private treeLabels: ResourceLabels;
private messageElement!: HTMLDivElement;
private tree: Tree | undefined;
private treeLabels: ResourceLabels | undefined;
private root: ITreeItem;
private elementsToRefresh: ITreeItem[] = [];
private menus: TitleMenus;
private markdownRenderer: MarkdownRenderer;
private markdownResult: IMarkdownRenderResult | null;
private readonly _onDidExpandItem: Emitter<ITreeItem> = this._register(new Emitter<ITreeItem>());
readonly onDidExpandItem: Event<ITreeItem> = this._onDidExpandItem.event;
@@ -212,69 +163,109 @@ export class CustomTreeView extends Disposable implements ITreeView {
private readonly _onDidChangeTitle: Emitter<string> = this._register(new Emitter<string>());
readonly onDidChangeTitle: Event<string> = this._onDidChangeTitle.event;
private readonly _onDidCompleteRefresh: Emitter<void> = this._register(new Emitter<void>());
private nodeContext: NodeContextKey;
constructor(
private id: string,
protected readonly id: string,
private _title: string,
private viewContainer: ViewContainer,
@IExtensionService private readonly extensionService: IExtensionService,
@IWorkbenchThemeService private readonly themeService: IWorkbenchThemeService,
@IThemeService private readonly themeService: IThemeService,
@IInstantiationService private readonly instantiationService: IInstantiationService,
@ICommandService private readonly commandService: ICommandService,
@IConfigurationService private readonly configurationService: IConfigurationService,
@IProgressService private readonly progressService: IProgressService,
@IProgressService protected readonly progressService: IProgressService,
@IContextMenuService private readonly contextMenuService: IContextMenuService,
@IKeybindingService private readonly keybindingService: IKeybindingService
@IKeybindingService private readonly keybindingService: IKeybindingService,
@INotificationService private readonly notificationService: INotificationService,
@IViewDescriptorService private readonly viewDescriptorService: IViewDescriptorService,
@IContextKeyService contextKeyService: IContextKeyService
) {
super();
this.root = new Root();
this.menus = this._register(instantiationService.createInstance(TitleMenus, this.id));
this._register(this.menus.onDidChangeTitle(() => this._onDidChangeActions.fire()));
this.collapseAllContextKey = new RawContextKey<boolean>(`treeView.${this.id}.enableCollapseAll`, false);
this.collapseAllContext = this.collapseAllContextKey.bindTo(contextKeyService);
this.refreshContextKey = new RawContextKey<boolean>(`treeView.${this.id}.enableRefresh`, false);
this.refreshContext = this.refreshContextKey.bindTo(contextKeyService);
this._register(this.themeService.onDidFileIconThemeChange(() => this.doRefresh([this.root]) /** soft refresh **/));
this._register(this.themeService.onDidColorThemeChange(() => this.doRefresh([this.root]) /** soft refresh **/));
this._register(this.configurationService.onDidChangeConfiguration(e => {
if (e.affectsConfiguration('explorer.decorations')) {
this.doRefresh([this.root]).catch(onUnexpectedError); /** soft refresh **/
this.doRefresh([this.root]); /** soft refresh **/
}
}));
this.markdownRenderer = instantiationService.createInstance(MarkdownRenderer);
this._register(toDisposable(() => {
if (this.markdownResult) {
this.markdownResult.dispose();
}
}));
this._register(Registry.as<IViewsRegistry>(Extensions.ViewsRegistry).onDidChangeContainer(({ views, from, to }) => {
if (from === this.viewContainer && views.some(v => v.id === this.id)) {
this.viewContainer = to;
this._register(this.viewDescriptorService.onDidChangeLocation(({ views, from, to }) => {
if (views.some(v => v.id === this.id)) {
this.tree?.updateOptions({ overrideStyles: { listBackground: this.viewLocation === ViewContainerLocation.Sidebar ? SIDE_BAR_BACKGROUND : PANEL_BACKGROUND } });
}
}));
this.registerActions();
this.nodeContext = this._register(instantiationService.createInstance(NodeContextKey));
this.nodeContext = this._register(instantiationService.createInstance(NodeContextKey)); // tracked change
this.create();
}
private _dataProvider: ITreeViewDataProvider | null;
get dataProvider(): ITreeViewDataProvider | null {
collapse(element: ITreeItem): boolean {
if (this.tree) {
return this.tree.collapse(element);
}
return false;
}
get viewContainer(): ViewContainer {
return this.viewDescriptorService.getViewContainerByViewId(this.id)!;
}
get viewLocation(): ViewContainerLocation {
return this.viewDescriptorService.getViewLocationById(this.id)!;
}
private _dataProvider: ITreeViewDataProvider | undefined;
get dataProvider(): ITreeViewDataProvider | undefined {
return this._dataProvider;
}
set dataProvider(dataProvider: ITreeViewDataProvider | null) {
set dataProvider(dataProvider: ITreeViewDataProvider | undefined) {
if (this.tree === undefined) {
this.createTree();
}
if (dataProvider) {
this._dataProvider = new class implements ITreeViewDataProvider {
private _isEmpty: boolean = true;
private _onDidChangeEmpty: Emitter<void> = new Emitter();
public onDidChangeEmpty: Event<void> = this._onDidChangeEmpty.event;
get isTreeEmpty(): boolean {
return this._isEmpty;
}
async getChildren(node: ITreeItem): Promise<ITreeItem[]> {
let children: ITreeItem[];
if (node && node.children) {
return Promise.resolve(node.children);
children = node.children;
} else {
children = await (node instanceof Root ? dataProvider.getChildren() : dataProvider.getChildren(node));
node.children = children;
}
if (node instanceof Root) {
const oldEmpty = this._isEmpty;
this._isEmpty = children.length === 0;
if (oldEmpty !== this._isEmpty) {
this._onDidChangeEmpty.fire();
}
}
const children = await (node instanceof Root ? dataProvider.getChildren() : dataProvider.getChildren(node));
node.children = children;
return children;
}
};
if (this._dataProvider.onDidChangeEmpty) {
this._register(this._dataProvider.onDidChangeEmpty(() => this._onDidChangeWelcomeState.fire()));
}
this.updateMessage();
this.refresh().catch(onUnexpectedError);
this.refresh();
} else {
this._dataProvider = null;
this._dataProvider = undefined;
this.updateMessage();
}
@@ -322,27 +313,61 @@ export class CustomTreeView extends Disposable implements ITreeView {
}
get showCollapseAllAction(): boolean {
return this._showCollapseAllAction;
return !!this.collapseAllContext.get();
}
set showCollapseAllAction(showCollapseAllAction: boolean) {
if (this._showCollapseAllAction !== !!showCollapseAllAction) {
this._showCollapseAllAction = !!showCollapseAllAction;
this._onDidChangeActions.fire();
}
this.collapseAllContext.set(showCollapseAllAction);
}
getPrimaryActions(): IAction[] {
if (this.showCollapseAllAction) {
const collapseAllAction = new Action('vs.tree.collapse', localize('collapseAll', "Collapse All"), 'monaco-tree-action collapse-all', true, () => this.tree ? new CollapseAllAction<ITreeItem, ITreeItem, FuzzyScore>(this.tree, true).run() : Promise.resolve());
return [...this.menus.getTitleActions(), collapseAllAction];
} else {
return this.menus.getTitleActions();
}
get showRefreshAction(): boolean {
return !!this.refreshContext.get();
}
getSecondaryActions(): IAction[] {
return this.menus.getTitleSecondaryActions();
set showRefreshAction(showRefreshAction: boolean) {
this.refreshContext.set(showRefreshAction);
}
private registerActions() {
const that = this;
this._register(registerAction2(class extends Action2 {
constructor() {
super({
id: `workbench.actions.treeView.${that.id}.refresh`,
title: localize('refresh', "Refresh"),
menu: {
id: MenuId.ViewTitle,
when: ContextKeyExpr.and(ContextKeyEqualsExpr.create('view', that.id), that.refreshContextKey),
group: 'navigation',
order: Number.MAX_SAFE_INTEGER - 1,
},
icon: { id: 'codicon/refresh' }
});
}
async run(): Promise<void> {
return that.refresh();
}
}));
this._register(registerAction2(class extends Action2 {
constructor() {
super({
id: `workbench.actions.treeView.${that.id}.collapseAll`,
title: localize('collapseAll', "Collapse All"),
menu: {
id: MenuId.ViewTitle,
when: ContextKeyExpr.and(ContextKeyEqualsExpr.create('view', that.id), that.collapseAllContextKey),
group: 'navigation',
order: Number.MAX_SAFE_INTEGER,
},
icon: { id: 'codicon/collapse-all' }
});
}
async run(): Promise<void> {
if (that.tree) {
return new CollapseAllAction<ITreeItem, ITreeItem, FuzzyScore>(that.tree, true).run();
}
}
}));
}
setVisibility(isVisible: boolean): void {
@@ -352,9 +377,6 @@ export class CustomTreeView extends Disposable implements ITreeView {
}
this.isVisible = isVisible;
if (this.isVisible) {
this.activate();
}
if (this.tree) {
if (this.isVisible) {
@@ -364,7 +386,7 @@ export class CustomTreeView extends Disposable implements ITreeView {
}
if (this.isVisible && this.elementsToRefresh.length) {
this.doRefresh(this.elementsToRefresh).catch(onUnexpectedError);
this.doRefresh(this.elementsToRefresh);
this.elementsToRefresh = [];
}
}
@@ -372,16 +394,18 @@ export class CustomTreeView extends Disposable implements ITreeView {
this._onDidChangeVisibility.fire(this.isVisible);
}
focus(): void {
focus(reveal: boolean = true): void {
if (this.tree && this.root.children && this.root.children.length > 0) {
// Make sure the current selected element is revealed
const selectedElement = this.tree.getSelection()[0];
if (selectedElement) {
if (selectedElement && reveal) {
this.tree.reveal(selectedElement, 0.5);
}
// Pass Focus to Viewer
this.tree.domFocus();
} else if (this.tree) {
this.tree.domFocus();
} else {
this.domNode.focus();
}
@@ -406,18 +430,21 @@ export class CustomTreeView extends Disposable implements ITreeView {
const actionViewItemProvider = (action: IAction) => action instanceof MenuItemAction ? this.instantiationService.createInstance(ContextAwareMenuEntryActionViewItem, action) : undefined;
const treeMenus = this._register(this.instantiationService.createInstance(TreeMenus, this.id));
this.treeLabels = this._register(this.instantiationService.createInstance(ResourceLabels, this));
const dataSource = this.instantiationService.createInstance(TreeDataSource, this, this.id, <T>(task: Promise<T>) => this.progressService.withProgress({ location: this.viewContainer.id }, () => task));
const dataSource = this.instantiationService.createInstance(TreeDataSource, this, this.id, <T>(task: Promise<T>) => this.progressService.withProgress({ location: this.id }, () => task));
const aligner = new Aligner(this.themeService);
const renderer = this.instantiationService.createInstance(TreeRenderer, this.id, treeMenus, this.treeLabels, actionViewItemProvider, aligner);
const widgetAriaLabel = this._title;
this.tree = this._register(this.instantiationService.createInstance(WorkbenchAsyncDataTree, 'SqlCustomView', this.treeContainer, new CustomTreeDelegate(), [renderer],
this.tree = this._register(this.instantiationService.createInstance(Tree, this.id, this.treeContainer, new TreeViewDelegate(), [renderer],
dataSource, {
identityProvider: new CustomViewIdentityProvider(),
identityProvider: new TreeViewIdentityProvider(),
accessibilityProvider: {
getAriaLabel(element: ITreeItem): string {
return element.label ? element.label.label : '';
return element.tooltip ? element.tooltip : element.label ? element.label.label : '';
},
getWidgetAriaLabel: () => this.title
getWidgetAriaLabel(): string {
return widgetAriaLabel;
}
},
keyboardNavigationLabelProvider: {
getKeyboardNavigationLabel: (item: ITreeItem) => {
@@ -429,15 +456,22 @@ export class CustomTreeView extends Disposable implements ITreeView {
return e.collapsibleState !== TreeItemCollapsibleState.Expanded;
},
multipleSelectionSupport: this.canSelectMany,
overrideStyles: {
listBackground: this.viewLocation === ViewContainerLocation.Sidebar ? SIDE_BAR_BACKGROUND : PANEL_BACKGROUND
}
}) as WorkbenchAsyncDataTree<ITreeItem, ITreeItem, FuzzyScore>);
aligner.tree = this.tree;
const actionRunner = new MultipleSelectionActionRunner(() => this.tree!.getSelection());
const actionRunner = new MultipleSelectionActionRunner(this.notificationService, () => this.tree!.getSelection());
renderer.actionRunner = actionRunner;
this.tree.contextKeyService.createKey<boolean>(this.id, true);
this._register(this.tree.onContextMenu(e => this.onContextMenu(treeMenus, e, actionRunner)));
this._register(this.tree.onDidChangeSelection(e => this._onDidChangeSelection.fire(e.elements)));
this._register(this.tree.onDidChangeCollapseState(e => {
if (!e.node.element) {
return;
}
const element: ITreeItem = Array.isArray(e.node.element.element) ? e.node.element.element[0] : e.node.element.element;
if (e.node.collapsed) {
this._onDidCollapseItem.fire(element);
@@ -446,18 +480,18 @@ export class CustomTreeView extends Disposable implements ITreeView {
}
}));
// Update resource context based on focused element
this._register(this.tree.onDidChangeFocus(e => {
this._register(this.tree.onDidChangeFocus(e => { // tracked change
this.nodeContext.set({ node: e.elements[0], viewId: this.id });
}));
this.tree.setInput(this.root).then(() => this.updateContentAreas());
const customTreeNavigator = new TreeResourceNavigator(this.tree, { openOnFocus: false, openOnSelection: false });
this._register(customTreeNavigator);
this._register(customTreeNavigator.onDidOpenResource(e => {
const treeNavigator = new TreeResourceNavigator(this.tree, { openOnFocus: false, openOnSelection: false });
this._register(treeNavigator);
this._register(treeNavigator.onDidOpenResource(e => {
if (!e.browserEvent) {
return;
}
const selection = this.tree.getSelection();
const selection = this.tree!.getSelection();
if ((selection.length === 1) && selection[0].command) {
this.commandService.executeCommand(selection[0].command.id, ...(selection[0].command.arguments || []));
}
@@ -474,7 +508,7 @@ export class CustomTreeView extends Disposable implements ITreeView {
event.preventDefault();
event.stopPropagation();
this.tree.setFocus([node]);
this.tree!.setFocus([node]);
const actions = treeMenus.getResourceContextActions(node);
if (!actions.length) {
return;
@@ -494,17 +528,17 @@ export class CustomTreeView extends Disposable implements ITreeView {
onHide: (wasCancelled?: boolean) => {
if (wasCancelled) {
this.tree.domFocus();
this.tree!.domFocus();
}
},
getActionsContext: () => (<TreeViewItemHandleArg>{ $treeViewId: this.id, $treeItemHandle: node.handle, $treeItem: node, $treeContainerId: this.treeContainer.id }),
getActionsContext: () => (<TreeViewItemHandleArg>{ $treeViewId: this.id, $treeItemHandle: node.handle }),
actionRunner
});
}
private updateMessage(): void {
protected updateMessage(): void {
if (this._message) {
this.showMessage(this._message);
} else if (!this.dataProvider) {
@@ -515,43 +549,36 @@ export class CustomTreeView extends Disposable implements ITreeView {
this.updateContentAreas();
}
private showMessage(message: string | IMarkdownString): void {
private showMessage(message: string): void {
DOM.removeClass(this.messageElement, 'hide');
if (this._messageValue !== message) {
this.resetMessageElement();
this._messageValue = message;
if (isString(this._messageValue)) {
this.messageElement.textContent = this._messageValue;
} else {
this.markdownResult = this.markdownRenderer.render(this._messageValue);
DOM.append(this.messageElement, this.markdownResult.element);
}
this.layout(this._size);
this.resetMessageElement();
this._messageValue = message;
if (!isFalsyOrWhitespace(this._message)) {
this.messageElement.textContent = this._messageValue;
}
this.layout(this._height, this._width);
}
private hideMessage(): void {
this.resetMessageElement();
DOM.addClass(this.messageElement, 'hide');
this.layout(this._size);
this.layout(this._height, this._width);
}
private resetMessageElement(): void {
if (this.markdownResult) {
this.markdownResult.dispose();
this.markdownResult = null;
}
DOM.clearNode(this.messageElement);
}
private _size: number;
layout(size: number) {
if (size) {
this._size = size;
const treeSize = size - DOM.getTotalHeight(this.messageElement);
this.treeContainer.style.height = treeSize + 'px';
private _height: number = 0;
private _width: number = 0;
layout(height: number, width: number) {
if (height && width) {
this._height = height;
this._width = width;
const treeHeight = height - DOM.getTotalHeight(this.messageElement);
this.treeContainer.style.height = treeHeight + 'px';
if (this.tree) {
this.tree.layout(treeSize);
this.tree.layout(treeHeight, width);
}
}
}
@@ -565,8 +592,11 @@ export class CustomTreeView extends Disposable implements ITreeView {
return 0;
}
refresh(elements?: ITreeItem[]): Promise<void> {
async refresh(elements?: ITreeItem[]): Promise<void> {
if (this.dataProvider && this.tree) {
if (this.refreshing) {
await Event.toPromise(this._onDidCompleteRefresh.event);
}
if (!elements) {
elements = [this.root];
// remove all waiting elements to refresh if root is asked to refresh
@@ -591,24 +621,17 @@ export class CustomTreeView extends Disposable implements ITreeView {
}
}
}
return Promise.resolve(undefined);
}
collapse(element: ITreeItem): boolean {
if (this.tree) {
return this.tree.collapse(element);
}
return Promise.arguments(null);
return undefined;
}
async expand(itemOrItems: ITreeItem | ITreeItem[]): Promise<void> {
if (this.tree) {
const tree = this.tree;
if (tree) {
itemOrItems = Array.isArray(itemOrItems) ? itemOrItems : [itemOrItems];
await Promise.all(itemOrItems.map(element => {
return this.tree.expand(element, false);
return tree.expand(element, false);
}));
}
return Promise.resolve(undefined);
}
setSelection(items: ITreeItem[]): void {
@@ -624,34 +647,23 @@ export class CustomTreeView extends Disposable implements ITreeView {
}
}
reveal(item: ITreeItem): Promise<void> {
async reveal(item: ITreeItem): Promise<void> {
if (this.tree) {
return Promise.resolve(this.tree.reveal(item));
}
return Promise.resolve();
}
private activate() {
if (!this.activated) {
this.createTree();
this.progressService.withProgress({ location: this.viewContainer.id }, () => this.extensionService.activateByEvent(`onView:${this.id}`))
.then(() => timeout(2000))
.then(() => {
this.updateMessage();
});
this.activated = true;
return this.tree.reveal(item);
}
}
private refreshing: boolean = false;
private async doRefresh(elements: ITreeItem[]): Promise<void> {
if (this.tree) {
const tree = this.tree;
if (tree && this.visible) {
this.refreshing = true;
await Promise.all(elements.map(element => this.tree.updateChildren(element, true)));
await Promise.all(elements.map(element => tree.updateChildren(element, true, true)));
this.refreshing = false;
this._onDidCompleteRefresh.fire();
this.updateContentAreas();
if (this.focused) {
this.focus();
this.focus(false);
}
}
}
@@ -669,13 +681,13 @@ export class CustomTreeView extends Disposable implements ITreeView {
}
}
class CustomViewIdentityProvider implements IIdentityProvider<ITreeItem> {
class TreeViewIdentityProvider implements IIdentityProvider<ITreeItem> {
getId(element: ITreeItem): { toString(): string; } {
return element.handle;
}
}
class CustomTreeDelegate implements IListVirtualDelegate<ITreeItem> {
class TreeViewDelegate implements IListVirtualDelegate<ITreeItem> {
getHeight(element: ITreeItem): number {
return TreeRenderer.ITEM_HEIGHT;
@@ -704,7 +716,7 @@ class TreeDataSource implements IAsyncDataSource<ITreeItem, ITreeItem> {
}
async getChildren(node: ITreeItem): Promise<any[]> {
if (node.childProvider) {
if (node.childProvider) { // tracked change
try {
return await this.withProgress(this.objectExplorerService.getChildren(node, this.id));
} catch (err) {
@@ -728,19 +740,18 @@ class TreeDataSource implements IAsyncDataSource<ITreeItem, ITreeItem> {
}
}
// todo@joh,sandy make this proper and contributable from extensions
registerThemingParticipant((theme, collector) => {
const findMatchHighlightColor = theme.getColor(editorFindMatchHighlight);
if (findMatchHighlightColor) {
collector.addRule(`.file-icon-themable-tree .monaco-list-row .content .monaco-highlighted-label .highlight { color: unset !important; background-color: ${findMatchHighlightColor}; }`);
collector.addRule(`.monaco-tl-contents .monaco-highlighted-label .highlight { color: unset !important; background-color: ${findMatchHighlightColor}; }`);
const matchBackgroundColor = theme.getColor(listFilterMatchHighlight);
if (matchBackgroundColor) {
collector.addRule(`.file-icon-themable-tree .monaco-list-row .content .monaco-highlighted-label .highlight { color: unset !important; background-color: ${matchBackgroundColor}; }`);
collector.addRule(`.monaco-tl-contents .monaco-highlighted-label .highlight { color: unset !important; background-color: ${matchBackgroundColor}; }`);
}
const findMatchHighlightColorBorder = theme.getColor(editorFindMatchHighlightBorder);
if (findMatchHighlightColorBorder) {
collector.addRule(`.file-icon-themable-tree .monaco-list-row .content .monaco-highlighted-label .highlight { color: unset !important; border: 1px dotted ${findMatchHighlightColorBorder}; box-sizing: border-box; }`);
collector.addRule(`.monaco-tl-contents .monaco-highlighted-label .highlight { color: unset !important; border: 1px dotted ${findMatchHighlightColorBorder}; box-sizing: border-box; }`);
const matchBorderColor = theme.getColor(listFilterMatchHighlightBorder);
if (matchBorderColor) {
collector.addRule(`.file-icon-themable-tree .monaco-list-row .content .monaco-highlighted-label .highlight { color: unset !important; border: 1px dotted ${matchBorderColor}; box-sizing: border-box; }`);
collector.addRule(`.monaco-tl-contents .monaco-highlighted-label .highlight { color: unset !important; border: 1px dotted ${matchBorderColor}; box-sizing: border-box; }`);
}
const link = theme.getColor(textLinkForeground);
if (link) {
@@ -776,7 +787,7 @@ class TreeRenderer extends Disposable implements ITreeRenderer<ITreeItem, FuzzyS
private labels: ResourceLabels,
private actionViewItemProvider: IActionViewItemProvider,
private aligner: Aligner,
@IWorkbenchThemeService private readonly themeService: IWorkbenchThemeService,
@IThemeService private readonly themeService: IThemeService,
@IConfigurationService private readonly configurationService: IConfigurationService,
@ILabelService private readonly labelService: ILabelService
) {
@@ -812,6 +823,23 @@ class TreeRenderer extends Disposable implements ITreeRenderer<ITreeItem, FuzzyS
const treeItemLabel: ITreeItemLabel | undefined = node.label ? node.label : resource ? { label: basename(resource) } : undefined;
const description = isString(node.description) ? node.description : resource && node.description === true ? this.labelService.getUriLabel(dirname(resource), { relative: true }) : undefined;
const label = treeItemLabel ? treeItemLabel.label : undefined;
const matches = (treeItemLabel && treeItemLabel.highlights && label) ? treeItemLabel.highlights.map(([start, end]) => {
if ((Math.abs(start) > label.length) || (Math.abs(end) >= label.length)) {
return ({ start: 0, end: 0 });
}
if (start < 0) {
start = label.length + start;
}
if (end < 0) {
end = label.length + end;
}
if (start > end) {
const swap = start;
start = end;
end = swap;
}
return ({ start, end });
}) : undefined;
const icon = this.themeService.getColorTheme().type === LIGHT ? node.icon : node.iconDark;
const iconUrl = icon ? URI.revive(icon) : null;
const title = node.tooltip ? node.tooltip : resource ? undefined : label;
@@ -820,18 +848,30 @@ class TreeRenderer extends Disposable implements ITreeRenderer<ITreeItem, FuzzyS
// reset
templateData.actionBar.clear();
if (resource || node.themeIcon) {
if (resource || this.isFileKindThemeIcon(node.themeIcon)) {
const fileDecorations = this.configurationService.getValue<{ colors: boolean, badges: boolean }>('explorer.decorations');
templateData.resourceLabel.setResource({ name: label, description, resource: resource ? resource : URI.parse('missing:_icon_resource') }, { fileKind: this.getFileKind(node), title, hideIcon: !!iconUrl, fileDecorations, extraClasses: ['custom-view-tree-node-item-resourceLabel'], matches: createMatches(element.filterData) });
templateData.resourceLabel.setResource({ name: label, description, resource: resource ? resource : URI.parse('missing:_icon_resource') }, { fileKind: this.getFileKind(node), title, hideIcon: !!iconUrl, fileDecorations, extraClasses: ['custom-view-tree-node-item-resourceLabel'], matches: matches ? matches : createMatches(element.filterData) });
} else {
templateData.resourceLabel.setResource({ name: label, description }, { title, hideIcon: true, extraClasses: ['custom-view-tree-node-item-resourceLabel'], matches: createMatches(element.filterData) });
templateData.resourceLabel.setResource({ name: label, description }, { title, hideIcon: true, extraClasses: ['custom-view-tree-node-item-resourceLabel'], matches: matches ? matches : createMatches(element.filterData) });
}
templateData.icon.title = title ? title : '';
if (iconUrl || sqlIcon) {
DOM.toggleClass(templateData.icon, sqlIcon, !!sqlIcon); // tracked change
DOM.toggleClass(templateData.icon, 'icon', !!sqlIcon);
templateData.icon.className = 'custom-view-tree-node-item-icon';
templateData.icon.style.backgroundImage = iconUrl ? DOM.asCSSUrl(iconUrl) : '';
} else {
let iconClass: string | undefined;
if (node.themeIcon && !this.isFileKindThemeIcon(node.themeIcon)) {
iconClass = ThemeIcon.asClassName(node.themeIcon);
}
templateData.icon.className = iconClass ? `custom-view-tree-node-item-icon ${iconClass}` : '';
templateData.icon.style.backgroundImage = '';
}
templateData.icon.className = '';
templateData.icon.style.backgroundImage = iconUrl ? `url('${DOM.asDomUri(iconUrl).toString(true)}')` : '';
DOM.toggleClass(templateData.icon, sqlIcon, !!sqlIcon);
DOM.toggleClass(templateData.icon, 'icon', !!sqlIcon);
DOM.toggleClass(templateData.icon, 'custom-view-tree-node-item-icon', !!iconUrl || !!sqlIcon);
templateData.actionBar.context = <TreeViewItemHandleArg>{ $treeViewId: this.treeViewId, $treeItemHandle: node.handle };
templateData.actionBar.push(this.menus.getResourceActions(node), { icon: true, label: false });
if (this._actionRunner) {
@@ -845,6 +885,14 @@ class TreeRenderer extends Disposable implements ITreeRenderer<ITreeItem, FuzzyS
DOM.toggleClass(container.parentElement!, 'align-icon-with-twisty', this.aligner.alignIconWithTwisty(treeItem));
}
private isFileKindThemeIcon(icon: ThemeIcon | undefined): boolean {
if (icon) {
return icon.id === FileThemeIcon.id || icon.id === FolderThemeIcon.id;
} else {
return false;
}
}
private getFileKind(node: ITreeItem): FileKind {
if (node.themeIcon) {
switch (node.themeIcon.id) {
@@ -869,9 +917,9 @@ class TreeRenderer extends Disposable implements ITreeRenderer<ITreeItem, FuzzyS
}
class Aligner extends Disposable {
private _tree: WorkbenchAsyncDataTree<ITreeItem, ITreeItem, FuzzyScore>;
private _tree: WorkbenchAsyncDataTree<ITreeItem, ITreeItem, FuzzyScore> | undefined;
constructor(private themeService: IWorkbenchThemeService) {
constructor(private themeService: IThemeService) {
super();
}
@@ -887,11 +935,15 @@ class Aligner extends Disposable {
return false;
}
const parent: ITreeItem = this._tree.getParentElement(treeItem) || this._tree.getInput();
if (this.hasIcon(parent)) {
if (this._tree) {
const parent: ITreeItem = this._tree.getParentElement(treeItem) || this._tree.getInput();
if (this.hasIcon(parent)) {
return false;
}
return !!parent.children && parent.children.every(c => c.collapsibleState === TreeItemCollapsibleState.None || !this.hasIcon(c));
} else {
return false;
}
return !!parent.children && parent.children.every(c => c.collapsibleState === TreeItemCollapsibleState.None || !this.hasIcon(c));
}
private hasIcon(node: ITreeItem): boolean {
@@ -913,22 +965,32 @@ class Aligner extends Disposable {
class MultipleSelectionActionRunner extends ActionRunner {
constructor(private getSelectedResources: (() => ITreeItem[])) {
constructor(notificationService: INotificationService, private getSelectedResources: (() => ITreeItem[])) {
super();
this._register(this.onDidRun(e => {
if (e.error) {
notificationService.error(localize('command-error', 'Error running command {1}: {0}. This is likely caused by the extension that contributes {1}.', e.error.message, e.action.id));
}
}));
}
runAction(action: IAction, context: TreeViewItemHandleArg): Promise<any> {
runAction(action: IAction, context: TreeViewItemHandleArg): Promise<void> {
const selection = this.getSelectedResources();
let selectionHandleArgs: TreeViewItemHandleArg[] | undefined = undefined;
let actionInSelected: boolean = false;
if (selection.length > 1) {
selectionHandleArgs = [];
selection.forEach(selected => {
if (selected.handle !== context.$treeItemHandle) {
selectionHandleArgs!.push({ $treeViewId: context.$treeViewId, $treeItemHandle: selected.handle });
selectionHandleArgs = selection.map(selected => {
if (selected.handle === context.$treeItemHandle) {
actionInSelected = true;
}
return { $treeViewId: context.$treeViewId, $treeItemHandle: selected.handle };
});
}
if (!actionInSelected) {
selectionHandleArgs = undefined;
}
return action.run(...[context, selectionHandleArgs]);
}
}
@@ -945,14 +1007,14 @@ class TreeMenus extends Disposable implements IDisposable {
}
getResourceActions(element: ITreeItem): IAction[] {
return this.mergeActions([
return this.mergeActions([ // tracked change
this.getActions(MenuId.ViewItemContext, { key: 'viewItem', value: element.contextValue }).primary,
this.getActions(MenuId.DataExplorerContext, { key: 'viewItem', value: element.contextValue }).primary
]);
}
getResourceContextActions(element: ITreeItem): IAction[] {
return this.mergeActions([
return this.mergeActions([ // tracked change
this.getActions(MenuId.ViewItemContext, { key: 'viewItem', value: element.contextValue }).secondary,
this.getActions(MenuId.DataExplorerContext, { key: 'viewItem', value: element.contextValue }).secondary
]);
@@ -962,7 +1024,7 @@ class TreeMenus extends Disposable implements IDisposable {
return actions.reduce((p, c) => p.concat(...c.filter(a => firstIndex(p, x => x.id === a.id) === -1)), [] as IAction[]);
}
private getActions(menuId: MenuId, context: { key: string, value: string }): { primary: IAction[]; secondary: IAction[]; } {
private getActions(menuId: MenuId, context: { key: string, value?: string }): { primary: IAction[]; secondary: IAction[]; } {
const contextKeyService = this.contextKeyService.createScoped();
contextKeyService.createKey('view', this.id);
contextKeyService.createKey(context.key, context.value);
@@ -980,38 +1042,43 @@ class TreeMenus extends Disposable implements IDisposable {
}
}
class MarkdownRenderer {
export class CustomTreeView extends TreeView {
private activated: boolean = false;
constructor(
@IOpenerService private readonly _openerService: IOpenerService
id: string,
title: string,
@IThemeService themeService: IThemeService,
@IInstantiationService instantiationService: IInstantiationService,
@ICommandService commandService: ICommandService,
@IConfigurationService configurationService: IConfigurationService,
@IProgressService progressService: IProgressService,
@IContextMenuService contextMenuService: IContextMenuService,
@IKeybindingService keybindingService: IKeybindingService,
@INotificationService notificationService: INotificationService,
@IViewDescriptorService viewDescriptorService: IViewDescriptorService,
@IContextKeyService contextKeyService: IContextKeyService,
@IExtensionService private readonly extensionService: IExtensionService,
) {
super(id, title, themeService, instantiationService, commandService, configurationService, progressService, contextMenuService, keybindingService, notificationService, viewDescriptorService, contextKeyService);
}
private getOptions(disposeables: DisposableStore): MarkdownRenderOptions {
return {
actionHandler: {
callback: (content) => {
let uri: URI | undefined;
try {
uri = URI.parse(content);
} catch {
// ignore
}
if (uri && this._openerService) {
this._openerService.open(uri).catch(onUnexpectedError);
}
},
disposeables
}
};
setVisibility(isVisible: boolean): void {
super.setVisibility(isVisible);
if (this.visible) {
this.activate();
}
}
render(markdown: IMarkdownString): IMarkdownRenderResult {
const disposeables = new DisposableStore();
const element: HTMLElement = markdown ? renderMarkdown(markdown, this.getOptions(disposeables)) : document.createElement('span');
return {
element,
dispose: () => disposeables.dispose()
};
private activate() {
if (!this.activated) {
this.progressService.withProgress({ location: this.id }, () => this.extensionService.activateByEvent(`onView:${this.id}`))
.then(() => timeout(2000))
.then(() => {
this.updateMessage();
});
this.activated = true;
}
}
}

View File

@@ -32,7 +32,7 @@ export interface ITreeItem extends vsITreeItem {
export interface ITreeView extends vsITreeView {
collapse(itemOrItems: ITreeItem): boolean;
collapse(element: ITreeItem): boolean
}

View File

@@ -91,13 +91,13 @@ export class Insight {
private findctor(type: ChartType | InsightType): IInsightCtor {
if (find(Graph.types, x => x === type as ChartType)) {
return Graph;
return Graph as IInsightCtor;
} else if (find(ImageInsight.types, x => x === type as InsightType)) {
return ImageInsight;
return ImageInsight as IInsightCtor;
} else if (find(TableInsight.types, x => x === type as InsightType)) {
return TableInsight;
return TableInsight as IInsightCtor;
} else if (find(CountInsight.types, x => x === type as InsightType)) {
return CountInsight;
return CountInsight as IInsightCtor;
}
return undefined;
}

View File

@@ -8,6 +8,7 @@ import { mixin } from 'sql/base/common/objects';
import * as types from 'vs/base/common/types';
import { IInsightOptions, InsightType, ChartType } from 'sql/workbench/contrib/charts/common/interfaces';
import { IInsightData } from 'sql/platform/dashboard/browser/insightRegistry';
import { BrandedService } from 'vs/platform/instantiation/common/instantiation';
export interface IPointDataSet {
data: Array<{ x: number | string, y: number }>;
@@ -42,6 +43,6 @@ export interface IInsight {
}
export interface IInsightCtor {
new(container: HTMLElement, options: IInsightOptions, ...services: { _serviceBrand: undefined; }[]): IInsight;
new <Services extends BrandedService[]>(container: HTMLElement, options: IInsightOptions, ...services: Services): IInsight;
readonly types: Array<InsightType | ChartType>;
}

View File

@@ -48,7 +48,7 @@ export class DashboardNavSection extends DashboardTab implements OnDestroy, OnCh
dashboardHelper.filterConfigs
];
private readonly _gridModifiers: Array<(item: Array<WidgetConfig>, originalConfig: Array<WidgetConfig>) => Array<WidgetConfig>> = [
private readonly _gridModifiers: Array<(item: Array<WidgetConfig>, originalConfig?: Array<WidgetConfig>) => Array<WidgetConfig>> = [
dashboardHelper.validateGridConfig
];

View File

@@ -12,7 +12,6 @@ import { ContextKeyExpr, IContextKeyService } from 'vs/platform/contextkey/commo
import { WidgetConfig } from 'sql/workbench/contrib/dashboard/browser/core/dashboardWidget';
import { Extensions, IInsightRegistry } from 'sql/platform/dashboard/browser/insightRegistry';
import { ConnectionManagementInfo } from 'sql/platform/connection/common/connectionManagementInfo';
import { DashboardServiceInterface } from 'sql/workbench/contrib/dashboard/browser/services/dashboardServiceInterface.service';
import { WIDGETS_CONTAINER } from 'sql/workbench/contrib/dashboard/browser/containers/dashboardWidgetContainer.contribution';
import { GRID_CONTAINER } from 'sql/workbench/contrib/dashboard/browser/containers/dashboardGridContainer.contribution';
import { WEBVIEW_CONTAINER } from 'sql/workbench/contrib/dashboard/browser/containers/dashboardWebviewContainer.contribution';
@@ -111,7 +110,7 @@ export function addProvider<T extends { connectionManagementService: SingleConne
* Adds the edition to the passed widgets and returns the new widgets
* @param widgets Array of widgets to add edition onto
*/
export function addEdition<T extends { connectionManagementService: SingleConnectionManagementService }>(config: WidgetConfig[], collection: DashboardServiceInterface): Array<WidgetConfig> {
export function addEdition<T extends { connectionManagementService: SingleConnectionManagementService }>(config: WidgetConfig[], collection: T): Array<WidgetConfig> {
const connectionInfo: ConnectionManagementInfo = collection.connectionManagementService.connectionInfo;
if (connectionInfo.serverInfo) {
const edition = connectionInfo.serverInfo.engineEditionId;

View File

@@ -107,7 +107,7 @@ export abstract class DashboardPage extends AngularDisposable implements IConfig
return this.dashboardService.scopedContextKeyService;
}
private readonly _gridModifiers: Array<(item: Array<WidgetConfig>, originalConfig: Array<WidgetConfig>) => Array<WidgetConfig>> = [
private readonly _gridModifiers: Array<(item: Array<WidgetConfig>, originalConfig?: Array<WidgetConfig>) => Array<WidgetConfig>> = [
dashboardHelper.validateGridConfig
];

View File

@@ -57,7 +57,7 @@ MenuRegistry.appendMenuItem(MenuId.ObjectExplorerItemContext, {
when: ContextKeyExpr.or(ContextKeyExpr.and(TreeNodeContextKey.Status.notEqualsTo('Unavailable'), TreeNodeContextKey.NodeType.isEqualTo('Server')), ContextKeyExpr.and(TreeNodeContextKey.Status.notEqualsTo('Unavailable'), TreeNodeContextKey.NodeType.isEqualTo('Database')))
});
const dashboardEditorDescriptor = new EditorDescriptor(
const dashboardEditorDescriptor = EditorDescriptor.create(
DashboardEditor,
DashboardEditor.ID,
localize('dashboard.editor.label', "Dashboard")

View File

@@ -7,16 +7,17 @@ import { localize } from 'vs/nls';
import { forEach } from 'vs/base/common/collections';
import { IJSONSchema } from 'vs/base/common/jsonSchema';
import { Registry } from 'vs/platform/registry/common/platform';
import { IViewContainersRegistry, ViewContainer, Extensions as ViewContainerExtensions, ITreeViewDescriptor, IViewsRegistry } from 'vs/workbench/common/views';
import { IViewContainersRegistry, ViewContainer, Extensions as ViewContainerExtensions, IViewsRegistry } from 'vs/workbench/common/views';
import { IExtensionPoint, ExtensionsRegistry, ExtensionMessageCollector } from 'vs/workbench/services/extensions/common/extensionsRegistry';
import { IWorkbenchContribution } from 'vs/workbench/common/contributions';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
import { coalesce } from 'vs/base/common/arrays';
import { CustomTreeViewPane, CustomTreeView } from 'sql/workbench/browser/parts/views/customView';
import { CustomTreeView, TreeViewPane } from 'sql/workbench/browser/parts/views/treeView';
import { VIEWLET_ID } from 'sql/workbench/contrib/dataExplorer/browser/dataExplorerViewlet';
import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
import { ICustomViewDescriptor } from 'vs/workbench/api/browser/viewsExtensionPoint';
interface IUserFriendlyViewDescriptor {
id: string;
@@ -103,14 +104,15 @@ export class DataExplorerContainerExtensionHandler implements IWorkbenchContribu
return null;
}
const viewDescriptor = <ITreeViewDescriptor>{
const viewDescriptor = <ICustomViewDescriptor>{
id: item.id,
name: item.name,
ctorDescriptor: new SyncDescriptor(CustomTreeViewPane),
ctorDescriptor: new SyncDescriptor(TreeViewPane),
when: ContextKeyExpr.deserialize(item.when),
canToggleVisibility: true,
canMoveView: true,
treeView: this.instantiationService.createInstance(CustomTreeView, item.id, item.name),
collapsed: this.showCollapsed(container),
treeView: this.instantiationService.createInstance(CustomTreeView, item.id, item.name, container),
extensionId: extension.description.identifier,
originalContainerId: entry.key
};

View File

@@ -12,7 +12,7 @@ import { Registry } from 'vs/platform/registry/common/platform';
import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
// Editor
const editDataEditorDescriptor = new EditorDescriptor(
const editDataEditorDescriptor = EditorDescriptor.create(
EditDataEditor,
EditDataEditor.ID,
'EditData'
@@ -22,7 +22,7 @@ Registry.as<IEditorRegistry>(Extensions.Editors)
.registerEditor(editDataEditorDescriptor, [new SyncDescriptor(EditDataInput)]);
// Editor
const editDataResultsEditorDescriptor = new EditorDescriptor(
const editDataResultsEditorDescriptor = EditorDescriptor.create(
EditDataResultsEditor,
EditDataResultsEditor.ID,
'EditDataResults'

View File

@@ -21,7 +21,7 @@ import { IEditorService } from 'vs/workbench/services/editor/common/editorServic
import * as queryContext from 'sql/workbench/contrib/query/common/queryContext';
import { Taskbar, ITaskbarContent } from 'sql/base/browser/ui/taskbar/taskbar';
import { IActionViewItem } from 'vs/base/browser/ui/actionbar/actionbar';
import { Action } from 'vs/base/common/actions';
import { IAction } from 'vs/base/common/actions';
import { IQueryModelService } from 'sql/workbench/services/query/common/queryModel';
import { IEditorDescriptorService } from 'sql/workbench/services/queryEditor/browser/editorDescriptorService';
import {
@@ -321,7 +321,7 @@ export class EditDataEditor extends BaseEditor {
// Create QueryTaskbar
this._taskbarContainer = DOM.append(parentElement, DOM.$('div'));
this._taskbar = new Taskbar(this._taskbarContainer, {
actionViewItemProvider: (action: Action) => this._getChangeMaxRowsAction(action)
actionViewItemProvider: (action: IAction) => this._getChangeMaxRowsAction(action)
});
// Create Actions for the toolbar
@@ -352,7 +352,7 @@ export class EditDataEditor extends BaseEditor {
/**
* Gets the IActionItem for the list of row number drop down
*/
private _getChangeMaxRowsAction(action: Action): IActionViewItem {
private _getChangeMaxRowsAction(action: IAction): IActionViewItem {
let actionID = ChangeMaxRowsAction.ID;
if (action.id === actionID) {
if (!this._changeMaxRowsActionItem) {

View File

@@ -25,8 +25,8 @@ export class ShowRecommendedExtensionsByScenarioAction extends Action {
run(): Promise<void> {
return this.viewletService.openViewlet(VIEWLET_ID, true)
.then(viewlet => viewlet?.getViewPaneContainer())
.then((viewlet: IExtensionsViewPaneContainer) => {
.then(viewlet => viewlet?.getViewPaneContainer() as IExtensionsViewPaneContainer)
.then(viewlet => {
viewlet.search('@' + this.scenarioType);
viewlet.focus();
});
@@ -51,8 +51,8 @@ export class InstallRecommendedExtensionsByScenarioAction extends Action {
run(): Promise<any> {
if (!this.recommendations.length) { return Promise.resolve(); }
return this.viewletService.openViewlet(VIEWLET_ID, true)
.then(viewlet => viewlet?.getViewPaneContainer())
.then((viewlet: IExtensionsViewPaneContainer) => {
.then(viewlet => viewlet?.getViewPaneContainer() as IExtensionsViewPaneContainer)
.then(viewlet => {
viewlet.search('@' + this.scenarioType);
viewlet.focus();
const names = this.recommendations.map(({ extensionId }) => extensionId);

View File

@@ -57,7 +57,7 @@ Registry.as<ILanguageAssociationRegistry>(LanguageAssociationExtensions.Language
.registerLanguageAssociation(NotebookEditorInputAssociation.languages, NotebookEditorInputAssociation);
Registry.as<IEditorRegistry>(EditorExtensions.Editors)
.registerEditor(new EditorDescriptor(NotebookEditor, NotebookEditor.ID, localize('notebookEditor.name', "Notebook Editor")), [new SyncDescriptor(UntitledNotebookInput), new SyncDescriptor(FileNotebookInput)]);
.registerEditor(EditorDescriptor.create(NotebookEditor, NotebookEditor.ID, localize('notebookEditor.name', "Notebook Editor")), [new SyncDescriptor(UntitledNotebookInput), new SyncDescriptor(FileNotebookInput)]);
Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench)
.registerWorkbenchContribution(NotebookThemingContribution, LifecyclePhase.Restored);

View File

@@ -14,7 +14,7 @@ import { ProfilerInput } from 'sql/workbench/browser/editor/profiler/profilerInp
import { ProfilerEditor } from 'sql/workbench/contrib/profiler/browser/profilerEditor';
import { PROFILER_VIEW_TEMPLATE_SETTINGS, PROFILER_SESSION_TEMPLATE_SETTINGS, IProfilerViewTemplate, IProfilerSessionTemplate, EngineType, PROFILER_FILTER_SETTINGS } from 'sql/workbench/services/profiler/browser/interfaces';
const profilerDescriptor = new EditorDescriptor(
const profilerDescriptor = EditorDescriptor.create(
ProfilerEditor,
ProfilerEditor.ID,
'ProfilerEditor'

View File

@@ -395,7 +395,7 @@ export class ProfilerEditor extends BaseEditor {
this._detailTable.updateRowCount();
});
const detailTableCopyKeybind = new CopyKeybind();
const detailTableCopyKeybind = new CopyKeybind<IDetailData>();
detailTableCopyKeybind.onCopy((ranges: Slick.Range[]) => {
// we always only get 1 item in the ranges
if (ranges && ranges.length === 1) {

View File

@@ -323,7 +323,7 @@ export abstract class GridTableBase<T> extends Disposable implements IView {
private table: Table<T>;
private actionBar: ActionBar;
private container = document.createElement('div');
private selectionModel = new CellSelectionModel();
private selectionModel = new CellSelectionModel<T>();
private styles: ITableStyles;
private currentHeight: number;
private dataProvider: AsyncDataProvider<T>;
@@ -461,7 +461,7 @@ export abstract class GridTableBase<T> extends Disposable implements IView {
this.renderGridDataRowsRange(startIndex, count);
});
this.rowNumberColumn = new RowNumberColumn({ numberOfRows: this.resultSet.rowCount });
let copyHandler = new CopyKeybind();
let copyHandler = new CopyKeybind<T>();
copyHandler.onCopy(e => {
new CopyResultAction(CopyResultAction.COPY_ID, CopyResultAction.COPY_LABEL, false).run(this.generateContext());
});

View File

@@ -57,10 +57,10 @@ Registry.as<ILanguageAssociationRegistry>(LanguageAssociationExtensions.Language
.registerLanguageAssociation(QueryEditorLanguageAssociation.languages, QueryEditorLanguageAssociation, QueryEditorLanguageAssociation.isDefault);
Registry.as<IEditorRegistry>(EditorExtensions.Editors)
.registerEditor(new EditorDescriptor(QueryResultsEditor, QueryResultsEditor.ID, localize('queryResultsEditor.name', "Query Results")), [new SyncDescriptor(QueryResultsInput)]);
.registerEditor(EditorDescriptor.create(QueryResultsEditor, QueryResultsEditor.ID, localize('queryResultsEditor.name', "Query Results")), [new SyncDescriptor(QueryResultsInput)]);
Registry.as<IEditorRegistry>(EditorExtensions.Editors)
.registerEditor(new EditorDescriptor(QueryEditor, QueryEditor.ID, localize('queryEditor.name', "Query Editor")), [new SyncDescriptor(FileQueryEditorInput), new SyncDescriptor(UntitledQueryEditorInput)]);
.registerEditor(EditorDescriptor.create(QueryEditor, QueryEditor.ID, localize('queryEditor.name', "Query Editor")), [new SyncDescriptor(FileQueryEditorInput), new SyncDescriptor(UntitledQueryEditorInput)]);
const actionRegistry = <IWorkbenchActionRegistry>Registry.as(ActionExtensions.WorkbenchActions);

View File

@@ -24,7 +24,7 @@ import { SplitView, Sizing } from 'vs/base/browser/ui/splitview/splitview';
import { Event } from 'vs/base/common/event';
import { DisposableStore } from 'vs/base/common/lifecycle';
import { ISelectionData } from 'azdata';
import { Action, IActionViewItem } from 'vs/base/common/actions';
import { IActionViewItem, IAction } from 'vs/base/common/actions';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { BaseTextEditor } from 'vs/workbench/browser/parts/editor/textEditor';
import { FileEditorInput } from 'vs/workbench/contrib/files/common/editors/fileEditorInput';
@@ -171,7 +171,7 @@ export class QueryEditor extends BaseEditor {
// Create QueryTaskbar
let taskbarContainer = DOM.append(parentElement, DOM.$('div'));
this.taskbar = this._register(new Taskbar(taskbarContainer, {
actionViewItemProvider: (action: Action) => this._getActionItemForAction(action),
actionViewItemProvider: action => this._getActionItemForAction(action),
}));
// Create Actions for the toolbar
@@ -236,7 +236,7 @@ export class QueryEditor extends BaseEditor {
* Gets the IActionItem for the List Databases dropdown if provided the associated Action.
* Otherwise returns null.
*/
private _getActionItemForAction(action: Action): IActionViewItem {
private _getActionItemForAction(action: IAction): IActionViewItem {
if (action.id === actions.ListDatabasesAction.ID) {
return this.listDatabasesActionItem;
}

View File

@@ -12,7 +12,7 @@ import { ILanguageAssociationRegistry, Extensions as LanguageAssociationExtensio
// Query Plan editor registration
const queryPlanEditorDescriptor = new EditorDescriptor(
const queryPlanEditorDescriptor = EditorDescriptor.create(
QueryPlanEditor,
QueryPlanEditor.ID,
'QueryPlan'

View File

@@ -48,7 +48,7 @@ export class StatusUpdater extends lifecycle.Disposable implements ext.IWorkbenc
lifecycle.dispose(this.badgeHandle);
let numOfInProgressTask: number = this.taskService.getNumberOfInProgressTasks();
let badge: NumberBadge = new NumberBadge(numOfInProgressTask, n => localize('inProgressTasksChangesBadge', "{0} in progress tasks", n));
this.badgeHandle = this.activityBarService.showActivity(TASKS_CONTAINER_ID, badge, 'taskhistory-viewlet-label');
this.badgeHandle = this.activityBarService.showViewContainerActivity(TASKS_CONTAINER_ID, { badge, clazz: 'taskhistory-viewlet-label' });
}
public getId(): string {

View File

@@ -46,6 +46,7 @@ import { IProductService } from 'vs/platform/product/common/productService';
import { KeyCode } from 'vs/base/common/keyCodes';
import { joinPath } from 'vs/base/common/resources';
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
import { addStandardDisposableListener, EventHelper } from 'vs/base/browser/dom';
const configurationKey = 'workbench.startupEditor';
const oldConfigurationKey = 'workbench.welcome.enabled';
@@ -321,23 +322,21 @@ class WelcomePage extends Disposable {
}
private createWidePreviewToolTip() {
const previewLink = document.querySelector('#tool_tip_container_wide');
const tooltip = document.querySelector('#tooltip_text_wide');
const previewLink = document.querySelector('#tool_tip_container_wide') as HTMLElement;
const tooltip = document.querySelector('#tooltip_text_wide') as HTMLElement;
const previewModalBody = document.querySelector('.preview_tooltip_body') as HTMLElement;
const previewModalHeader = document.querySelector('.preview_tooltip_header') as HTMLElement;
previewLink.addEventListener('mouseover', () => {
addStandardDisposableListener(previewLink, 'mouseover', () => {
tooltip.setAttribute('aria-hidden', 'true');
tooltip.classList.toggle('show');
});
previewLink.addEventListener('mouseout', () => {
addStandardDisposableListener(previewLink, 'mouseout', () => {
tooltip.setAttribute('aria-hidden', 'false');
tooltip.classList.remove('show');
});
previewLink.addEventListener('keydown', (e: KeyboardEvent) => {
let event = new StandardKeyboardEvent(e);
addStandardDisposableListener(previewLink, 'keydown', event => {
if (event.equals(KeyCode.Escape)) {
if (tooltip.classList.contains('show')) {
tooltip.setAttribute('aria-hidden', 'true');
@@ -351,9 +350,7 @@ class WelcomePage extends Disposable {
}
});
tooltip.addEventListener('keydown', (e: KeyboardEvent) => {
let event = new StandardKeyboardEvent(e);
addStandardDisposableListener(tooltip, 'keydown', event => {
if (event.equals(KeyCode.Escape)) {
if (tooltip.classList.contains('show')) {
tooltip.setAttribute('aria-hidden', 'true');
@@ -361,8 +358,8 @@ class WelcomePage extends Disposable {
}
}
else if (event.equals(KeyCode.Tab)) {
e.preventDefault();
if (e.target === previewModalBody) {
EventHelper.stop(event);
if (event.target === previewModalBody) {
previewModalHeader.focus();
} else {
previewModalBody.focus();
@@ -381,15 +378,14 @@ class WelcomePage extends Disposable {
}
private createDropDown() {
const dropdownBtn = document.querySelector('#dropdown_btn');
const dropdownBtn = document.querySelector('#dropdown_btn') as HTMLElement;
const dropdown = document.querySelector('#dropdown') as HTMLInputElement;
dropdownBtn.addEventListener('click', () => {
addStandardDisposableListener(dropdownBtn, 'click', () => {
dropdown.classList.toggle('show');
});
dropdownBtn.addEventListener('keydown', (e: KeyboardEvent) => {
let event = new StandardKeyboardEvent(e);
addStandardDisposableListener(dropdownBtn, 'keydown', event => {
if (event.equals(KeyCode.Enter) || event.equals(KeyCode.Space)) {
const dropdownFirstElement = document.querySelector('#dropdown').firstElementChild.children[0] as HTMLInputElement;
dropdown.classList.toggle('show');
@@ -397,8 +393,7 @@ class WelcomePage extends Disposable {
}
});
dropdown.addEventListener('keydown', (e: KeyboardEvent) => {
let event = new StandardKeyboardEvent(e);
addStandardDisposableListener(dropdown, 'keydown', event => {
if (event.equals(KeyCode.Escape)) {
if (dropdown.classList.contains('show')) {
dropdown.classList.remove('show');
@@ -427,16 +422,15 @@ class WelcomePage extends Disposable {
}
});
dropdown.addEventListener('keydown', function (e: KeyboardEvent) {
addStandardDisposableListener(dropdown, 'keydown', event => {
const dropdownLastElement = document.querySelector('#dropdown').lastElementChild.children[0] as HTMLInputElement;
const dropdownFirstElement = document.querySelector('#dropdown').firstElementChild.children[0] as HTMLInputElement;
let event = new StandardKeyboardEvent(e);
if (event.equals(KeyCode.Tab)) {
e.preventDefault();
EventHelper.stop(event);
return;
}
else if (event.equals(KeyCode.UpArrow) || event.equals(KeyCode.LeftArrow)) {
if (e.target === dropdownFirstElement) {
if (event.target === dropdownFirstElement) {
dropdownLastElement.focus();
} else {
const movePrev = <HTMLElement>document.querySelector('.move:focus').parentElement.previousElementSibling.children[0] as HTMLElement;
@@ -444,7 +438,7 @@ class WelcomePage extends Disposable {
}
}
else if (event.equals(KeyCode.DownArrow) || event.equals(KeyCode.RightArrow)) {
if (e.target === dropdownLastElement) {
if (event.target === dropdownLastElement) {
dropdownFirstElement.focus();
} else {
const moveNext = <HTMLElement>document.querySelector('.move:focus').parentElement.nextElementSibling.children[0] as HTMLElement;

View File

@@ -52,16 +52,16 @@ const labelDisplay = nls.localize("insights.item", "Item");
const valueDisplay = nls.localize("insights.value", "Value");
const iconClass = 'codicon';
class InsightTableView<T> extends ViewPane {
private _table: Table<T>;
public get table(): Table<T> {
class InsightTableView extends ViewPane {
private _table: Table<ListResource>;
public get table(): Table<ListResource> {
return this._table;
}
constructor(
private columns: Slick.Column<T>[],
private data: IDisposableDataProvider<T> | Array<T>,
private tableOptions: Slick.GridOptions<T>,
private columns: Slick.Column<ListResource>[],
private data: IDisposableDataProvider<ListResource> | Array<ListResource>,
private tableOptions: Slick.GridOptions<ListResource>,
options: IViewPaneOptions,
@IKeybindingService keybindingService: IKeybindingService,
@IContextMenuService contextMenuService: IContextMenuService,
@@ -220,14 +220,14 @@ export class InsightsDialogView extends Modal {
const itemsHeaderTitle = nls.localize("insights.dialog.items", "Items");
const itemsDetailHeaderTitle = nls.localize("insights.dialog.itemDetails", "Item Details");
this._topTableData = new TableDataView();
this._bottomTableData = new TableDataView();
let topTableView = this._instantiationService.createInstance(InsightTableView, this._topColumns, this._topTableData, { forceFitColumns: true }, { id: 'insights.top', title: itemsHeaderTitle }) as InsightTableView<ListResource>;
this._topTableData = new TableDataView<ListResource>();
this._bottomTableData = new TableDataView<ListResource>();
let topTableView = this._instantiationService.createInstance(InsightTableView, this._topColumns, this._topTableData, { forceFitColumns: true }, { id: 'insights.top', title: itemsHeaderTitle });
topTableView.render();
attachPanelStyler(topTableView, this._themeService);
this._topTable = topTableView.table;
this._topTable.setSelectionModel(new RowSelectionModel<ListResource>());
let bottomTableView = this._instantiationService.createInstance(InsightTableView, this._bottomColumns, this._bottomTableData, { forceFitColumns: true }, { id: 'insights.bottom', title: itemsDetailHeaderTitle }) as InsightTableView<ListResource>;
let bottomTableView = this._instantiationService.createInstance(InsightTableView, this._bottomColumns, this._bottomTableData, { forceFitColumns: true }, { id: 'insights.bottom', title: itemsDetailHeaderTitle });
bottomTableView.render();
attachPanelStyler(bottomTableView, this._themeService);
this._bottomTable = bottomTableView.table;
@@ -275,8 +275,8 @@ export class InsightsDialogView extends Modal {
this._register(attachTableStyler(this._topTable, this._themeService));
this._register(attachTableStyler(this._bottomTable, this._themeService));
this._topTable.grid.onKeyDown.subscribe((e: KeyboardEvent) => {
let event = new StandardKeyboardEvent(e);
this._topTable.grid.onKeyDown.subscribe(e => {
let event = new StandardKeyboardEvent(<unknown>e as KeyboardEvent);
if (event.equals(KeyMod.Shift | KeyCode.Tab)) {
topTableView.focus();
e.stopImmediatePropagation();
@@ -286,8 +286,8 @@ export class InsightsDialogView extends Modal {
}
});
this._bottomTable.grid.onKeyDown.subscribe((e: KeyboardEvent) => {
let event = new StandardKeyboardEvent(e);
this._bottomTable.grid.onKeyDown.subscribe(e => {
let event = new StandardKeyboardEvent(<unknown>e as KeyboardEvent);
if (event.equals(KeyMod.Shift | KeyCode.Tab)) {
bottomTableView.focus();
e.stopImmediatePropagation();

View File

@@ -53,7 +53,7 @@ const languageAssociationRegistry = new class implements ILanguageAssociationReg
}
}
registerLanguageAssociation<Services extends BrandedService[]>(languages: string[], contribution: ILanguageAssociationSignature<Services>, isDefault?: boolean): IDisposable {
registerLanguageAssociation(languages: string[], contribution: ILanguageAssociationSignature<BrandedService[]>, isDefault?: boolean): IDisposable {
for (const language of languages) {
this.associationContructors.set(language, contribution);
}

View File

@@ -379,8 +379,8 @@ export class RestoreDialog extends Modal {
}
});
this._restorePlanTable.grid.onKeyDown.subscribe((e: KeyboardEvent) => {
let event = new StandardKeyboardEvent(e);
this._restorePlanTable.grid.onKeyDown.subscribe(e => {
let event = new StandardKeyboardEvent(<unknown>e as KeyboardEvent);
if (event.equals(KeyMod.Shift | KeyCode.Tab)) {
this._destinationRestoreToInputBox.isEnabled() ? this._destinationRestoreToInputBox.focus() : this._databaseDropdown.focus();
e.stopImmediatePropagation();
@@ -390,8 +390,8 @@ export class RestoreDialog extends Modal {
}
});
this._fileListTable.grid.onKeyDown.subscribe((e: KeyboardEvent) => {
let event = new StandardKeyboardEvent(e);
this._fileListTable.grid.onKeyDown.subscribe(e => {
let event = new StandardKeyboardEvent(<unknown>e as KeyboardEvent);
if (event.equals(KeyMod.Shift | KeyCode.Tab)) {
if ((<InputBox>this._optionsMap[this._relocatedLogFileFolderOption]).isEnabled()) {
(<InputBox>this._optionsMap[this._relocatedLogFileFolderOption]).focus();