提交 3175eab4 编写于 作者: R Rob Lourens

Initial exclude control

上级 0d45ae7a
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="3 3 16 16" enable-background="new 3 3 16 16"><polygon fill="#e8e8e8" points="12.597,11.042 15.4,13.845 13.844,15.4 11.042,12.598 8.239,15.4 6.683,13.845 9.485,11.042 6.683,8.239 8.238,6.683 11.042,9.486 13.845,6.683 15.4,8.239"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="3 3 16 16" enable-background="new 3 3 16 16"><polygon fill="#424242" points="12.597,11.042 15.4,13.845 13.844,15.4 11.042,12.598 8.239,15.4 6.683,13.845 9.485,11.042 6.683,8.239 8.238,6.683 11.042,9.486 13.845,6.683 15.4,8.239"/></svg>
\ No newline at end of file
......@@ -302,7 +302,7 @@
border-radius: 3px;
margin-right: 4px;
margin-left: 0px;
margin-top: 4px;
margin-top: 2px;
padding: 0px;
background-size: 14px !important;
}
......@@ -348,6 +348,103 @@
height: 26px;
}
.settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-exclude .setting-item-value > .setting-item-control {
width: 100%;
}
.settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-exclude .setting-exclude-pattern {
margin-right: 3px;
}
.settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-exclude .setting-exclude-pattern,
.settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-exclude .setting-exclude-sibling {
display: inline-block;
}
.settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-exclude .setting-exclude-sibling {
opacity: 0.7;
margin-left: 0.5em;
font-size: 0.9em;
white-space: pre;
}
.settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-exclude .monaco-action-bar {
display: none;
position: absolute;
right: 0px;
}
.settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-exclude .monaco-list-row:hover .monaco-action-bar,
.settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-exclude .monaco-list-row.focused .monaco-action-bar {
display: block;
}
.settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-exclude .monaco-list-row .monaco-action-bar .action-label {
width: 16px;
height: 16px;
margin-top: 2px;
}
.settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-exclude .monaco-list-row .monaco-action-bar .setting-excludeAction-edit {
margin-right: 7px;
}
.vs .settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-exclude .monaco-list-row .monaco-action-bar .setting-excludeAction-edit {
background: url(edit.svg) center center no-repeat;
}
.vs-dark .settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-exclude .monaco-list-row .monaco-action-bar .setting-excludeAction-edit {
background: url(edit_inverse.svg) center center no-repeat;
}
.vs .settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-exclude .monaco-list-row .monaco-action-bar .setting-excludeAction-remove {
background: url(action-remove.svg) center center no-repeat;
}
.vs-dark .settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-exclude .monaco-list-row .monaco-action-bar .setting-excludeAction-remove {
background: url(action-remove-dark.svg) center center no-repeat;
}
.settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-exclude .monaco-text-button {
width: initial;
}
.settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-exclude .monaco-text-button.setting-exclude-addPattern {
margin-right: 5px;
}
.settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-exclude .monaco-text-button.setting-exclude-addButton {
display: none;
}
.settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-exclude.is-expanded .monaco-text-button.setting-exclude-addButton {
display: inline-block;
}
.settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-exclude .setting-exclude-checkbox {
height: 16px;
width: 16px;
border: 1px solid transparent;
border-radius: 3px;
margin-right: 4px;
margin-left: 0px;
margin-top: 4px;
padding: 0px;
background-size: 14px !important;
}
.vs .settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-exclude .setting-exclude-checkbox.checked {
background: url('check.svg') center center no-repeat;
}
.vs-dark .settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-exclude .setting-exclude-checkbox.checked {
background: url('check-inverse.svg') center center no-repeat;
}
.settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-exclude .monaco-list {
margin-bottom: 10px
}
.settings-editor > .settings-body > .settings-tree-container .group-title,
.settings-editor > .settings-body > .settings-tree-container .setting-item {
padding-left: 9px;
......
......@@ -7,28 +7,31 @@ import * as DOM from 'vs/base/browser/dom';
import { renderMarkdown } from 'vs/base/browser/htmlContentRenderer';
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
import { IMouseEvent } from 'vs/base/browser/mouseEvent';
import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar';
import { Button } from 'vs/base/browser/ui/button/button';
import { Checkbox } from 'vs/base/browser/ui/checkbox/checkbox';
import { InputBox } from 'vs/base/browser/ui/inputbox/inputBox';
import { IRenderer, IVirtualDelegate } from 'vs/base/browser/ui/list/list';
import { SelectBox } from 'vs/base/browser/ui/selectBox/selectBox';
import { Action } from 'vs/base/common/actions';
import * as arrays from 'vs/base/common/arrays';
import { Color, RGBA } from 'vs/base/common/color';
import { onUnexpectedError } from 'vs/base/common/errors';
import { Emitter, Event } from 'vs/base/common/event';
import { KeyCode } from 'vs/base/common/keyCodes';
import { dispose, IDisposable } from 'vs/base/common/lifecycle';
import { Disposable, dispose, IDisposable } from 'vs/base/common/lifecycle';
import * as objects from 'vs/base/common/objects';
import { escapeRegExpCharacters, startsWith } from 'vs/base/common/strings';
import URI from 'vs/base/common/uri';
import { TPromise } from 'vs/base/common/winjs.base';
import { IAccessibilityProvider, IDataSource, IFilter, IRenderer, ITree, ITreeConfiguration } from 'vs/base/parts/tree/browser/tree';
import { IAccessibilityProvider, IDataSource, IFilter, IRenderer as ITreeRenderer, ITree, ITreeConfiguration } from 'vs/base/parts/tree/browser/tree';
import { DefaultTreestyler } from 'vs/base/parts/tree/browser/treeDefaults';
import { localize } from 'vs/nls';
import { ConfigurationTarget, IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { IContextViewService } from 'vs/platform/contextview/browser/contextView';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { IListService, WorkbenchTree, WorkbenchTreeController } from 'vs/platform/list/browser/listService';
import { IListService, WorkbenchList, WorkbenchTree, WorkbenchTreeController } from 'vs/platform/list/browser/listService';
import { IOpenerService } from 'vs/platform/opener/common/opener';
import { editorBackground, focusBorder, foreground, inputBackground, inputBorder, inputForeground, registerColor, selectBackground, selectBorder, selectForeground, textLinkForeground } from 'vs/platform/theme/common/colorRegistry';
import { attachButtonStyler, attachInputBoxStyler, attachSelectBoxStyler, attachStyler } from 'vs/platform/theme/common/styler';
......@@ -474,6 +477,14 @@ interface ISettingComplexItemTemplate extends ISettingItemTemplate<void> {
button: Button;
}
interface ISettingExcludeItemTemplate extends ISettingItemTemplate<void> {
excludeWidget: ExcludeSettingWidget;
}
function isExcludeSetting(element: SettingsTreeSettingElement): boolean {
return element.setting.key === 'files.exclude';
}
interface IGroupTitleTemplate extends IDisposableTemplate {
context?: SettingsTreeGroupElement;
parent: HTMLElement;
......@@ -483,6 +494,7 @@ const SETTINGS_TEXT_TEMPLATE_ID = 'settings.text.template';
const SETTINGS_NUMBER_TEMPLATE_ID = 'settings.number.template';
const SETTINGS_ENUM_TEMPLATE_ID = 'settings.enum.template';
const SETTINGS_BOOL_TEMPLATE_ID = 'settings.bool.template';
const SETTINGS_EXCLUDE_TEMPLATE_ID = 'settings.exclude.template';
const SETTINGS_COMPLEX_TEMPLATE_ID = 'settings.complex.template';
const SETTINGS_GROUP_ELEMENT_TEMPLATE_ID = 'settings.group.template';
......@@ -491,7 +503,7 @@ export interface ISettingChangeEvent {
value: any; // undefined => reset/unconfigure
}
export class SettingsRenderer implements IRenderer {
export class SettingsRenderer implements ITreeRenderer {
private static readonly SETTING_ROW_HEIGHT = 98;
private static readonly SETTING_BOOL_ROW_HEIGHT = 65;
......@@ -513,6 +525,7 @@ export class SettingsRenderer implements IRenderer {
@IThemeService private themeService: IThemeService,
@IContextViewService private contextViewService: IContextViewService,
@IOpenerService private readonly openerService: IOpenerService,
@IInstantiationService private readonly instantiationService: IInstantiationService,
) {
this.measureContainer = DOM.append(_measureContainer, $('.setting-measure-container.monaco-tree-row'));
}
......@@ -530,6 +543,10 @@ export class SettingsRenderer implements IRenderer {
const isSelected = this.elementIsSelected(tree, element);
if (isSelected) {
return this.measureSettingElementHeight(tree, element);
} else if (isExcludeSetting(element)) {
// TODO@roblou measure or static calc?
// return this.measureSettingElementHeight(tree, element);
return Object.keys(element.value).length * 22 + 75;
} else {
return this._getUnexpandedSettingHeight(element);
}
......@@ -581,6 +598,10 @@ export class SettingsRenderer implements IRenderer {
return SETTINGS_ENUM_TEMPLATE_ID;
}
if (isExcludeSetting(element)) {
return SETTINGS_EXCLUDE_TEMPLATE_ID;
}
return SETTINGS_COMPLEX_TEMPLATE_ID;
}
......@@ -608,6 +629,10 @@ export class SettingsRenderer implements IRenderer {
return this.renderSettingEnumTemplate(tree, container);
}
if (templateId === SETTINGS_EXCLUDE_TEMPLATE_ID) {
return this.renderSettingExcludeTemplate(tree, container);
}
if (templateId === SETTINGS_COMPLEX_TEMPLATE_ID) {
return this.renderSettingComplexTemplate(tree, container);
}
......@@ -796,6 +821,29 @@ export class SettingsRenderer implements IRenderer {
return template;
}
private renderSettingExcludeTemplate(tree: ITree, container: HTMLElement): ISettingExcludeItemTemplate {
const common = this.renderCommonTemplate(tree, container, 'exclude');
const excludeWidget = this.instantiationService.createInstance(ExcludeSettingWidget, common.controlElement);
common.toDispose.push(excludeWidget);
// common.toDispose.push(excludeWidget.onDidClick(() => this._onDidOpenSettings.fire()));
// excludeWidget.label = localize('editInSettingsJson', "Edit in settings.json");
// excludeWidget.element.classList.add('edit-in-settings-button');
// common.toDispose.push(attachButtonStyler(excludeWidget, this.themeService, {
// buttonBackground: Color.transparent.toString(),
// buttonHoverBackground: Color.transparent.toString(),
// buttonForeground: 'foreground'
// }));
const template: ISettingExcludeItemTemplate = {
...common,
excludeWidget
};
return template;
}
private renderSettingComplexTemplate(tree: ITree, container: HTMLElement): ISettingComplexItemTemplate {
const common = this.renderCommonTemplate(tree, container, 'complex');
......@@ -918,8 +966,10 @@ export class SettingsRenderer implements IRenderer {
this.renderNumber(element, isSelected, <ISettingTextItemTemplate>template, onChange);
} else if (templateId === SETTINGS_BOOL_TEMPLATE_ID) {
this.renderBool(element, isSelected, <ISettingBoolItemTemplate>template, onChange);
} else if (templateId === SETTINGS_EXCLUDE_TEMPLATE_ID) {
this.renderExcludeSetting(element, isSelected, <ISettingExcludeItemTemplate>template);
} else if (templateId === SETTINGS_COMPLEX_TEMPLATE_ID) {
this.renderEditInSettingsJson(element, isSelected, <ISettingComplexItemTemplate>template);
this.renderComplexSetting(element, isSelected, <ISettingComplexItemTemplate>template);
}
}
......@@ -965,7 +1015,11 @@ export class SettingsRenderer implements IRenderer {
const parseFn = dataElement.valueType === 'integer' ? parseInt : parseFloat;
}
private renderEditInSettingsJson(dataElement: SettingsTreeSettingElement, isSelected: boolean, template: ISettingComplexItemTemplate): void {
private renderExcludeSetting(dataElement: SettingsTreeSettingElement, isSelected: boolean, template: ISettingExcludeItemTemplate): void {
template.excludeWidget.setValue(dataElement.value);
}
private renderComplexSetting(dataElement: SettingsTreeSettingElement, isSelected: boolean, template: ISettingComplexItemTemplate): void {
template.button.element.tabIndex = isSelected ? 0 : -1;
template.onChange = () => this._onDidOpenSettings.fire();
......@@ -1260,3 +1314,260 @@ export class SettingsTree extends NonExpandableTree {
}));
}
}
enum AddItemMode {
None,
Pattern,
PatternWithSibling
}
export class ExcludeSettingListModel {
private _dataItems: IExcludeItem[];
private _newItem: AddItemMode;
get items(): IExcludeItem[] {
const items = [
...this._dataItems
];
if (this._newItem === AddItemMode.Pattern) {
items.push(<INewExcludeItem>{
id: 'newItem',
withSibling: false
});
}
return items;
}
setValue(excludeValue: any): void {
this._dataItems = this.excludeValueToItems(excludeValue);
}
private excludeValueToItems(excludeValue: any): IExcludeItem[] {
return Object.keys(excludeValue).map(key => {
const value = excludeValue[key];
const enabled = !!value;
const sibling = typeof value === 'boolean' ? undefined : value.when;
return {
id: key,
enabled,
pattern: key,
sibling
};
});
}
}
export class ExcludeSettingWidget extends Disposable {
private list: WorkbenchList<IExcludeItem>;
private model = new ExcludeSettingListModel();
constructor(
container: HTMLElement,
@IThemeService private themeService: IThemeService,
@IInstantiationService private instantiationService: IInstantiationService
) {
super();
const dataRenderer = new ExcludeDataItemRenderer();
const newItemRenderer = this.instantiationService.createInstance(NewExcludeRenderer);
const delegate = new ExcludeSettingListDelegate();
this.list = this.instantiationService.createInstance(WorkbenchList, container, delegate, [newItemRenderer, dataRenderer], {
identityProvider: element => element.id,
multipleSelectionSupport: false
}) as WorkbenchList<IExcludeItem>;
this._register(this.list);
const addPatternButton = this._register(new Button(container));
addPatternButton.label = localize('addPattern', "Add Pattern");
addPatternButton.element.classList.add('setting-exclude-addPattern', 'setting-exclude-addButton');
this._register(attachButtonStyler(addPatternButton, this.themeService));
const addSiblingPatternButton = this._register(new Button(container));
addSiblingPatternButton.label = localize('addSiblingPattern', "Add Sibling Pattern");
addSiblingPatternButton.element.classList.add('setting-exclude-addButton');
this._register(attachButtonStyler(addSiblingPatternButton, this.themeService));
this._register(addSiblingPatternButton.onDidClick(() => {
}));
}
setValue(excludeValue: any): void {
this.model.setValue(excludeValue);
this.list.splice(0, this.list.length, this.model.items);
const listHeight = 22 * this.model.items.length;
this.list.layout(listHeight);
this.list.getHTMLElement().style.height = listHeight + 'px';
}
}
interface IExcludeDataItem {
id: string;
enabled: boolean;
pattern: string;
sibling?: string;
}
interface INewExcludeItem {
id: string;
withSibling: boolean;
}
type IExcludeItem = IExcludeDataItem | INewExcludeItem;
function isExcludeDataItem(excludeItem: IExcludeItem): excludeItem is IExcludeDataItem {
return !!(<IExcludeDataItem>excludeItem).pattern;
}
interface IExcludeDataItemTemplate {
container: HTMLElement;
checkbox: Checkbox;
actionBar: ActionBar;
patternElement: HTMLElement;
siblingElement: HTMLElement;
toDispose: IDisposable[];
}
class ExcludeDataItemRenderer implements IRenderer<IExcludeDataItem, IExcludeDataItemTemplate> {
static readonly templateId: string = 'excludeDataItem';
get templateId(): string {
return ExcludeDataItemRenderer.templateId;
}
renderTemplate(container: HTMLElement): IExcludeDataItemTemplate {
const toDispose = [];
const checkbox = new Checkbox({ actionClassName: 'setting-exclude-checkbox', isChecked: true, title: '', inputActiveOptionBorder: null });
container.appendChild(checkbox.domNode);
toDispose.push(checkbox);
toDispose.push(checkbox.onChange(() => {
// if (template.onChange) {
// template.onChange(checkbox.checked);
// }
}));
const actionBar = new ActionBar(container);
toDispose.push(actionBar);
const editAction = new EditExcludeItemAction();
const removeAction = new RemoveExcludeItemAction();
toDispose.push(editAction, removeAction);
actionBar.push([
editAction, removeAction
], { icon: true, label: false });
return {
container,
checkbox,
patternElement: DOM.append(container, $('.setting-exclude-pattern')),
siblingElement: DOM.append(container, $('.setting-exclude-sibling')),
toDispose,
actionBar
};
}
renderElement(element: IExcludeDataItem, index: number, templateData: IExcludeDataItemTemplate): void {
templateData.patternElement.textContent = element.pattern;
templateData.siblingElement.textContent = element.sibling;
}
disposeElement(element: IExcludeDataItem, index: number, templateData: IExcludeDataItemTemplate): void {
}
disposeTemplate(templateData: IExcludeDataItemTemplate): void {
dispose(templateData.toDispose);
}
}
interface INewExcludeItemTemplate {
container: HTMLElement;
patternInput: InputBox;
toDispose: IDisposable[];
}
class NewExcludeRenderer implements IRenderer<INewExcludeItem, INewExcludeItemTemplate> {
static readonly templateId: string = 'newExcludeItem';
constructor(
@IContextViewService private contextViewService: IContextViewService
) {
}
get templateId(): string {
return ExcludeDataItemRenderer.templateId;
}
renderTemplate(container: HTMLElement): INewExcludeItemTemplate {
const toDispose = [];
const patternInput = new InputBox(container, this.contextViewService);
toDispose.push(patternInput);
return {
container,
patternInput,
toDispose
};
}
renderElement(element: INewExcludeItem, index: number, templateData: INewExcludeItemTemplate): void {
}
disposeElement(element: INewExcludeItem, index: number, templateData: INewExcludeItemTemplate): void {
}
disposeTemplate(templateData: INewExcludeItemTemplate): void {
dispose(templateData.toDispose);
}
}
class ExcludeSettingListDelegate implements IVirtualDelegate<IExcludeItem> {
getHeight(element: IExcludeItem): number {
return 22;
}
getTemplateId(element: IExcludeItem): string {
if (isExcludeDataItem(element)) {
return ExcludeDataItemRenderer.templateId;
} else {
return NewExcludeRenderer.templateId;
}
}
}
class EditExcludeItemAction extends Action {
static readonly ID = 'workbench.action.editExcludeItem';
static readonly LABEL = localize('editExcludeItem', "Edit Exclude Item");
constructor() {
super(EditExcludeItemAction.ID, EditExcludeItemAction.LABEL);
this.class = 'setting-excludeAction-edit';
}
run(item: IExcludeItem): TPromise<boolean> {
return TPromise.wrap(true);
}
}
class RemoveExcludeItemAction extends Action {
static readonly ID = 'workbench.action.removeExcludeItem';
static readonly LABEL = localize('removeExcludeItem', "Remove Exclude Item");
constructor() {
super(RemoveExcludeItemAction.ID, RemoveExcludeItemAction.LABEL);
this.class = 'setting-excludeAction-remove';
}
run(item: IExcludeItem): TPromise<boolean> {
return TPromise.wrap(true);
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册