tocTree.ts 7.8 KB
Newer Older
R
Rob Lourens 已提交
1 2 3 4 5 6 7
/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/

import * as DOM from 'vs/base/browser/dom';
import { TPromise } from 'vs/base/common/winjs.base';
8 9
import { IDataSource, IRenderer, ITree, ITreeConfiguration } from 'vs/base/parts/tree/browser/tree';
import { DefaultTreestyler, OpenMode } from 'vs/base/parts/tree/browser/treeDefaults';
10
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
11 12 13
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { IListService, WorkbenchTree, WorkbenchTreeController } from 'vs/platform/list/browser/listService';
14
import { editorBackground, focusBorder } from 'vs/platform/theme/common/colorRegistry';
15 16 17 18 19
import { attachStyler } from 'vs/platform/theme/common/styler';
import { ICssStyleCollector, ITheme, IThemeService, registerThemingParticipant } from 'vs/platform/theme/common/themeService';
import { ISettingsEditorViewState, SearchResultModel, SettingsAccessibilityProvider, SettingsTreeElement, SettingsTreeFilter, SettingsTreeGroupElement, SettingsTreeSettingElement } from 'vs/workbench/parts/preferences/browser/settingsTree';
import { settingsHeaderForeground } from 'vs/workbench/parts/preferences/browser/settingsWidgets';
import { ISetting } from 'vs/workbench/services/preferences/common/preferences';
R
Rob Lourens 已提交
20 21 22

const $ = DOM.$;

23
export class TOCTreeModel {
24

25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
	private _currentSearchModel: SearchResultModel;
	private _settingsTreeRoot: SettingsTreeGroupElement;

	public set settingsTreeRoot(value: SettingsTreeGroupElement) {
		this._settingsTreeRoot = value;
		this.update();
	}

	public set currentSearchModel(model: SearchResultModel) {
		this._currentSearchModel = model;
		this.update();
	}

	public get children(): SettingsTreeElement[] {
		return this._settingsTreeRoot.children;
	}

	public update(): void {
		this.updateGroupCount(this._settingsTreeRoot);
	}

	private updateGroupCount(group: SettingsTreeGroupElement): void {
		(<any>group).count = this._currentSearchModel ?
			this.getSearchResultChildrenCount(group) :
			undefined;

		group.children.forEach(child => {
			if (child instanceof SettingsTreeGroupElement) {
				this.updateGroupCount(child);
			}
		});
	}

	private getSearchResultChildrenCount(group: SettingsTreeGroupElement): number {
59
		return this._currentSearchModel.getChildren().filter(child => {
60
			return child instanceof SettingsTreeSettingElement && this.groupContainsSetting(group, child.setting);
61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78
		}).length;
	}

	private groupContainsSetting(group: SettingsTreeGroupElement, setting: ISetting): boolean {
		return group.children.some(child => {
			if (child instanceof SettingsTreeSettingElement) {
				return child.setting.key === setting.key;
			} else if (child instanceof SettingsTreeGroupElement) {
				return this.groupContainsSetting(child, setting);
			} else {
				return false;
			}
		});
	}
}

export type TOCTreeElement = SettingsTreeGroupElement | TOCTreeModel;

R
Rob Lourens 已提交
79
export class TOCDataSource implements IDataSource {
80 81 82 83 84
	constructor(
		@IConfigurationService private configService: IConfigurationService
	) {
	}

85
	getId(tree: ITree, element: SettingsTreeGroupElement): string {
R
Rob Lourens 已提交
86 87 88
		return element.id;
	}

89 90 91
	hasChildren(tree: ITree, element: TOCTreeElement): boolean {
		return element instanceof TOCTreeModel ||
			(element instanceof SettingsTreeGroupElement && element.children && element.children.every(child => child instanceof SettingsTreeGroupElement));
R
Rob Lourens 已提交
92 93
	}

J
Joao Moreno 已提交
94
	getChildren(tree: ITree, element: TOCTreeElement): TPromise<SettingsTreeElement[]> {
95 96 97 98
		return TPromise.as(this._getChildren(element));
	}

	private _getChildren(element: TOCTreeElement): SettingsTreeElement[] {
R
Rob Lourens 已提交
99
		// TODO@roblou hack. Clean up or remove this option
100
		if (this.configService.getValue('workbench.settings.settingsSearchTocBehavior') === 'filter') {
R
Rob Lourens 已提交
101
			const children = element.children as SettingsTreeElement[]; // TS????
102 103 104 105 106 107
			return children.filter(group => {
				return (<any>group).count !== 0;
			});
		}

		return element.children;
R
Rob Lourens 已提交
108 109
	}

J
Joao Moreno 已提交
110
	getParent(tree: ITree, element: TOCTreeElement): TPromise<any> {
111
		return TPromise.wrap(element instanceof SettingsTreeGroupElement && element.parent);
R
Rob Lourens 已提交
112 113 114 115 116 117
	}
}

const TOC_ENTRY_TEMPLATE_ID = 'settings.toc.entry';

interface ITOCEntryTemplate {
118 119
	labelElement: HTMLElement;
	countElement: HTMLElement;
R
Rob Lourens 已提交
120 121 122
}

export class TOCRenderer implements IRenderer {
123
	getHeight(tree: ITree, element: SettingsTreeElement): number {
R
Rob Lourens 已提交
124 125 126
		return 22;
	}

127
	getTemplateId(tree: ITree, element: SettingsTreeElement): string {
R
Rob Lourens 已提交
128 129 130 131 132
		return TOC_ENTRY_TEMPLATE_ID;
	}

	renderTemplate(tree: ITree, templateId: string, container: HTMLElement): ITOCEntryTemplate {
		return {
133 134
			labelElement: DOM.append(container, $('.settings-toc-entry')),
			countElement: DOM.append(container, $('.settings-toc-count'))
R
Rob Lourens 已提交
135 136 137
		};
	}

138
	renderElement(tree: ITree, element: SettingsTreeGroupElement, templateId: string, template: ITOCEntryTemplate): void {
139 140
		const count = (<any>element).count;
		const label = element.label;
141

142 143
		DOM.toggleClass(template.labelElement, 'no-results', count === 0);
		template.labelElement.textContent = label;
144

145
		if (count) {
146 147 148
			template.countElement.textContent = ` (${count})`;
		} else {
			template.countElement.textContent = '';
149
		}
R
Rob Lourens 已提交
150 151 152 153 154
	}

	disposeTemplate(tree: ITree, templateId: string, templateData: any): void {
	}
}
155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171

export class TOCTree extends WorkbenchTree {
	constructor(
		container: HTMLElement,
		viewState: ISettingsEditorViewState,
		configuration: Partial<ITreeConfiguration>,
		@IContextKeyService contextKeyService: IContextKeyService,
		@IListService listService: IListService,
		@IThemeService themeService: IThemeService,
		@IInstantiationService instantiationService: IInstantiationService,
		@IConfigurationService configurationService: IConfigurationService
	) {
		const treeClass = 'settings-toc-tree';

		const fullConfiguration = <ITreeConfiguration>{
			controller: instantiationService.createInstance(WorkbenchTreeController, { openMode: OpenMode.DOUBLE_CLICK }),
			filter: instantiationService.createInstance(SettingsTreeFilter, viewState),
172
			styler: new DefaultTreestyler(DOM.createStyleSheet(container), treeClass),
173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208
			dataSource: instantiationService.createInstance(TOCDataSource),
			accessibilityProvider: instantiationService.createInstance(SettingsAccessibilityProvider),

			...configuration
		};

		const options = {
			showLoading: false,
			twistiePixels: 15
		};

		super(container,
			fullConfiguration,
			options,
			contextKeyService,
			listService,
			themeService,
			instantiationService,
			configurationService);

		this.disposables.push(registerThemingParticipant((theme: ITheme, collector: ICssStyleCollector) => {
			const activeBorderColor = theme.getColor(focusBorder);
			if (activeBorderColor) {
				collector.addRule(`.settings-editor > .settings-body > .settings-toc-container .monaco-tree:focus .monaco-tree-row.focused { outline-color: ${activeBorderColor}; }`);
			}
		}));

		this.getHTMLElement().classList.add(treeClass);

		this.disposables.push(attachStyler(themeService, {
			listActiveSelectionBackground: editorBackground,
			listActiveSelectionForeground: settingsHeaderForeground,
			listFocusAndSelectionBackground: editorBackground,
			listFocusAndSelectionForeground: settingsHeaderForeground,
			listFocusBackground: editorBackground,
			listFocusForeground: settingsHeaderForeground,
209
			listHoverForeground: settingsHeaderForeground,
210 211 212 213 214 215 216 217
			listHoverBackground: editorBackground,
			listInactiveSelectionBackground: editorBackground,
			listInactiveSelectionForeground: settingsHeaderForeground,
		}, colors => {
			this.style(colors);
		}));
	}
}