Files
azuredatastudio/src/vs/workbench/contrib/preferences/browser/tocTree.ts

229 lines
7.5 KiB
TypeScript

/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as DOM from 'vs/base/browser/dom';
import { IListVirtualDelegate } from 'vs/base/browser/ui/list/list';
import { DefaultStyleController, IAccessibilityProvider } from 'vs/base/browser/ui/list/listWidget';
import { IObjectTreeOptions, ObjectTree } from 'vs/base/browser/ui/tree/objectTree';
import { ITreeElement, ITreeNode, ITreeRenderer } from 'vs/base/browser/ui/tree/tree';
import { Iterable } from 'vs/base/common/iterator';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { editorBackground, transparent, foreground } from 'vs/platform/theme/common/colorRegistry';
import { attachStyler } from 'vs/platform/theme/common/styler';
import { IThemeService } from 'vs/platform/theme/common/themeService';
import { SettingsTreeFilter } from 'vs/workbench/contrib/preferences/browser/settingsTree';
import { ISettingsEditorViewState, SearchResultModel, SettingsTreeElement, SettingsTreeGroupElement, SettingsTreeSettingElement } from 'vs/workbench/contrib/preferences/browser/settingsTreeModels';
import { settingsHeaderForeground } from 'vs/workbench/contrib/preferences/browser/settingsWidgets';
import { localize } from 'vs/nls';
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
const $ = DOM.$;
export class TOCTreeModel {
private _currentSearchModel: SearchResultModel | null = null;
private _settingsTreeRoot!: SettingsTreeGroupElement;
constructor(
private _viewState: ISettingsEditorViewState,
@IWorkbenchEnvironmentService private environmentService: IWorkbenchEnvironmentService
) {
}
get settingsTreeRoot(): SettingsTreeGroupElement {
return this._settingsTreeRoot;
}
set settingsTreeRoot(value: SettingsTreeGroupElement) {
this._settingsTreeRoot = value;
this.update();
}
get currentSearchModel(): SearchResultModel | null {
return this._currentSearchModel;
}
set currentSearchModel(model: SearchResultModel | null) {
this._currentSearchModel = model;
this.update();
}
get children(): SettingsTreeElement[] {
return this._settingsTreeRoot.children;
}
update(): void {
if (this._settingsTreeRoot) {
this.updateGroupCount(this._settingsTreeRoot);
}
}
private updateGroupCount(group: SettingsTreeGroupElement): void {
group.children.forEach(child => {
if (child instanceof SettingsTreeGroupElement) {
this.updateGroupCount(child);
}
});
const childCount = group.children
.filter(child => child instanceof SettingsTreeGroupElement)
.reduce((acc, cur) => acc + (<SettingsTreeGroupElement>cur).count!, 0);
group.count = childCount + this.getGroupCount(group);
}
private getGroupCount(group: SettingsTreeGroupElement): number {
return group.children.filter(child => {
if (!(child instanceof SettingsTreeSettingElement)) {
return false;
}
if (this._currentSearchModel && !this._currentSearchModel.root.containsSetting(child.setting.key)) {
return false;
}
// Check everything that the SettingsFilter checks except whether it's filtered by a category
const isRemote = !!this.environmentService.configuration.remoteAuthority;
return child.matchesScope(this._viewState.settingsTarget, isRemote) && child.matchesAllTags(this._viewState.tagFilters) && child.matchesAnyExtension(this._viewState.extensionFilters);
}).length;
}
}
const TOC_ENTRY_TEMPLATE_ID = 'settings.toc.entry';
interface ITOCEntryTemplate {
labelElement: HTMLElement;
countElement: HTMLElement;
}
export class TOCRenderer implements ITreeRenderer<SettingsTreeGroupElement, never, ITOCEntryTemplate> {
templateId = TOC_ENTRY_TEMPLATE_ID;
renderTemplate(container: HTMLElement): ITOCEntryTemplate {
return {
labelElement: DOM.append(container, $('.settings-toc-entry')),
countElement: DOM.append(container, $('.settings-toc-count'))
};
}
renderElement(node: ITreeNode<SettingsTreeGroupElement>, index: number, template: ITOCEntryTemplate): void {
const element = node.element;
const count = element.count;
const label = element.label;
template.labelElement.textContent = label;
template.labelElement.title = label;
if (count) {
template.countElement.textContent = ` (${count})`;
} else {
template.countElement.textContent = '';
}
}
disposeTemplate(templateData: ITOCEntryTemplate): void {
}
}
class TOCTreeDelegate implements IListVirtualDelegate<SettingsTreeElement> {
getTemplateId(element: SettingsTreeElement): string {
return TOC_ENTRY_TEMPLATE_ID;
}
getHeight(element: SettingsTreeElement): number {
return 22;
}
}
export function createTOCIterator(model: TOCTreeModel | SettingsTreeGroupElement, tree: TOCTree): Iterable<ITreeElement<SettingsTreeGroupElement>> {
const groupChildren = <SettingsTreeGroupElement[]>model.children.filter(c => c instanceof SettingsTreeGroupElement);
return Iterable.map(groupChildren, g => {
const hasGroupChildren = g.children.some(c => c instanceof SettingsTreeGroupElement);
return {
element: g,
collapsed: undefined,
collapsible: hasGroupChildren,
children: g instanceof SettingsTreeGroupElement ?
createTOCIterator(g, tree) :
undefined
};
});
}
class SettingsAccessibilityProvider implements IAccessibilityProvider<SettingsTreeGroupElement> {
getAriaLabel(element: SettingsTreeElement): string {
if (!element) {
return '';
}
if (element instanceof SettingsTreeGroupElement) {
return localize('groupRowAriaLabel', "{0}, group", element.label);
}
return '';
}
getAriaLevel(element: SettingsTreeGroupElement): number {
let i = 1;
while (element instanceof SettingsTreeGroupElement && element.parent) {
i++;
element = element.parent;
}
return i;
}
}
export class TOCTree extends ObjectTree<SettingsTreeGroupElement> {
constructor(
container: HTMLElement,
viewState: ISettingsEditorViewState,
@IThemeService themeService: IThemeService,
@IInstantiationService instantiationService: IInstantiationService
) {
// test open mode
const filter = instantiationService.createInstance(SettingsTreeFilter, viewState);
const options: IObjectTreeOptions<SettingsTreeGroupElement> = {
filter,
multipleSelectionSupport: false,
identityProvider: {
getId(e) {
return e.id;
}
},
styleController: id => new DefaultStyleController(DOM.createStyleSheet(container), id),
accessibilityProvider: instantiationService.createInstance(SettingsAccessibilityProvider),
collapseByDefault: true
};
super('SettingsTOC', container,
new TOCTreeDelegate(),
[new TOCRenderer()],
options);
this.disposables.add(attachStyler(themeService, {
listBackground: editorBackground,
listActiveSelectionBackground: editorBackground,
listActiveSelectionForeground: settingsHeaderForeground,
listFocusAndSelectionBackground: editorBackground,
listFocusAndSelectionForeground: settingsHeaderForeground,
listFocusBackground: editorBackground,
listFocusForeground: transparent(foreground, 0.9),
listHoverForeground: transparent(foreground, 0.9),
listHoverBackground: editorBackground,
listInactiveSelectionBackground: editorBackground,
listInactiveSelectionForeground: settingsHeaderForeground,
listInactiveFocusBackground: editorBackground,
listInactiveFocusOutline: editorBackground
}, colors => {
this.style(colors);
}));
}
}