markersPanelActions.ts 10.6 KB
Newer Older
1 2 3 4 5
/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/

6
import { Delayer } from 'vs/base/common/async';
7
import * as DOM from 'vs/base/browser/dom';
S
Sandeep Somavarapu 已提交
8
import { TPromise } from 'vs/base/common/winjs.base';
S
Sandeep Somavarapu 已提交
9
import { Action, IAction } from 'vs/base/common/actions';
10
import { HistoryInputBox } from 'vs/base/browser/ui/inputbox/inputBox';
A
Alexandru Dima 已提交
11
import { KeyCode } from 'vs/base/common/keyCodes';
J
Johannes Rieken 已提交
12 13
import { IKeyboardEvent } from 'vs/base/browser/keyboardEvent';
import { IContextViewService } from 'vs/platform/contextview/browser/contextView';
14
import { TogglePanelAction } from 'vs/workbench/browser/panel';
15 16
import Messages from 'vs/workbench/parts/markers/electron-browser/messages';
import Constants from 'vs/workbench/parts/markers/electron-browser/constants';
17
import { IPartService } from 'vs/workbench/services/part/common/partService';
18
import { IPanelService } from 'vs/workbench/services/panel/common/panelService';
19
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
S
Sandeep Somavarapu 已提交
20
import { CollapseAllAction as TreeCollapseAction } from 'vs/base/parts/tree/browser/treeDefaults';
21
import * as Tree from 'vs/base/parts/tree/browser/tree';
B
Benjamin Pasero 已提交
22
import { IThemeService } from 'vs/platform/theme/common/themeService';
23
import { attachInputBoxStyler, attachStylerCallback, attachCheckboxStyler } from 'vs/platform/theme/common/styler';
24
import { IMarkersWorkbenchService } from 'vs/workbench/parts/markers/electron-browser/markers';
S
Sandeep Somavarapu 已提交
25
import { Event, Emitter } from 'vs/base/common/event';
26
import { IDisposable } from 'vs/base/common/lifecycle';
S
Sandeep Somavarapu 已提交
27 28
import { BaseActionItem } from 'vs/base/browser/ui/actionbar/actionbar';
import { badgeBackground, contrastBorder } from 'vs/platform/theme/common/colorRegistry';
29
import { localize } from 'vs/nls';
30
import { Checkbox } from 'vs/base/browser/ui/checkbox/checkbox';
31
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
S
#50583  
Sandeep Somavarapu 已提交
32
import { ContextScopedHistoryInputBox } from 'vs/platform/widget/browser/input';
33

34
export class ToggleMarkersPanelAction extends TogglePanelAction {
35

M
Matt Bierner 已提交
36 37
	public static readonly ID = 'workbench.actions.view.problems';
	public static readonly LABEL = Messages.MARKERS_PANEL_TOGGLE_LABEL;
38

39
	constructor(id: string, label: string,
40
		@IPartService partService: IPartService,
41
		@IPanelService panelService: IPanelService,
S
Sandeep Somavarapu 已提交
42
		@IMarkersWorkbenchService markersWorkbenchService: IMarkersWorkbenchService
43
	) {
44
		super(id, label, Constants.MARKERS_PANEL_ID, panelService, partService);
45 46 47
	}
}

S
Sandeep Somavarapu 已提交
48 49
export class ShowProblemsPanelAction extends Action {

M
Matt Bierner 已提交
50 51
	public static readonly ID = 'workbench.action.problems.focus';
	public static readonly LABEL = Messages.MARKERS_PANEL_SHOW_LABEL;
S
Sandeep Somavarapu 已提交
52 53

	constructor(id: string, label: string,
K
kieferrm 已提交
54
		@IPanelService private panelService: IPanelService
S
Sandeep Somavarapu 已提交
55 56 57 58 59 60 61 62 63
	) {
		super(id, label);
	}

	public run(): TPromise<any> {
		return this.panelService.openPanel(Constants.MARKERS_PANEL_ID, true);
	}
}

S
Sandeep Somavarapu 已提交
64 65
export class CollapseAllAction extends TreeCollapseAction {

K
kieferrm 已提交
66
	constructor(viewer: Tree.ITree, enabled: boolean) {
S
Sandeep Somavarapu 已提交
67 68
		super(viewer, enabled);
	}
69
}
70

71
export class MarkersFilterAction extends Action {
72

M
Matt Bierner 已提交
73
	public static readonly ID: string = 'workbench.actions.problems.filter';
S
Sandeep Somavarapu 已提交
74

S
Sandeep Somavarapu 已提交
75
	constructor() {
76
		super(MarkersFilterAction.ID, Messages.MARKERS_PANEL_ACTION_TOOLTIP_FILTER, 'markers-panel-action-filter', true);
77 78 79 80
	}

}

81 82 83 84 85 86 87
export interface IMarkersFilterActionItemOptions {
	filterText: string;
	filterHistory: string[];
	useFilesExclude: boolean;
}

export class MarkersFilterActionItem extends BaseActionItem {
S
Sandeep Somavarapu 已提交
88 89 90 91 92

	private _toDispose: IDisposable[] = [];

	private readonly _onDidChange: Emitter<void> = this._register(new Emitter<void>());
	readonly onDidChange: Event<void> = this._onDidChange.event;
93

94
	private delayedFilterUpdate: Delayer<void>;
S
Sandeep Somavarapu 已提交
95
	private container: HTMLElement;
96
	private filterInputBox: HistoryInputBox;
97
	private controlsContainer: HTMLInputElement;
S
Sandeep Somavarapu 已提交
98
	private filterBadge: HTMLInputElement;
99
	private filesExcludeFilter: Checkbox;
100

S
Sandeep Somavarapu 已提交
101
	constructor(
102
		private itemOptions: IMarkersFilterActionItemOptions,
S
Sandeep Somavarapu 已提交
103
		action: IAction,
104
		@IInstantiationService private instantiationService: IInstantiationService,
J
Johannes Rieken 已提交
105
		@IContextViewService private contextViewService: IContextViewService,
B
Benjamin Pasero 已提交
106
		@IThemeService private themeService: IThemeService,
S
Sandeep Somavarapu 已提交
107
		@IMarkersWorkbenchService private markersWorkbenchService: IMarkersWorkbenchService,
S
Sandeep Somavarapu 已提交
108 109 110
		@ITelemetryService private telemetryService: ITelemetryService
	) {
		super(null, action);
J
Johannes Rieken 已提交
111
		this.delayedFilterUpdate = new Delayer<void>(500);
S
Sandeep Somavarapu 已提交
112 113 114 115 116 117
	}

	render(container: HTMLElement): void {
		this.container = container;
		DOM.addClass(this.container, 'markers-panel-action-filter');
		this.createInput(this.container);
118 119
		this.createControls(this.container);
		this.adjustInputBox();
S
Sandeep Somavarapu 已提交
120 121
	}

122 123 124 125
	clear(): void {
		this.filterInputBox.value = '';
	}

S
Sandeep Somavarapu 已提交
126
	getFilterText(): string {
127
		return this.filterInputBox ? this.filterInputBox.value : this.itemOptions.filterText;
S
Sandeep Somavarapu 已提交
128 129 130
	}

	getFilterHistory(): string[] {
131
		return this.filterInputBox.getHistory();
132 133
	}

134 135 136 137 138 139 140 141 142 143 144 145 146
	get useFilesExclude(): boolean {
		return this.filesExcludeFilter ? this.filesExcludeFilter.checked : this.itemOptions.useFilesExclude;
	}

	set useFilesExclude(useFilesExclude: boolean) {
		if (this.filesExcludeFilter) {
			if (this.filesExcludeFilter.checked !== useFilesExclude) {
				this.filesExcludeFilter.checked = useFilesExclude;
				this._onDidChange.fire();
			}
		}
	}

S
Sandeep Somavarapu 已提交
147 148 149 150 151 152 153 154
	toggleLayout(small: boolean) {
		if (this.container) {
			DOM.toggleClass(this.container, 'small', small);
			DOM.toggleClass(this.filterBadge, 'small', small);
		}
	}

	private createInput(container: HTMLElement): void {
S
#50583  
Sandeep Somavarapu 已提交
155
		this.filterInputBox = this._register(this.instantiationService.createInstance(ContextScopedHistoryInputBox, container, this.contextViewService, {
156
			placeholder: Messages.MARKERS_PANEL_FILTER_PLACEHOLDER,
157 158 159
			ariaLabel: Messages.MARKERS_PANEL_FILTER_ARIA_LABEL,
			history: this.itemOptions.filterHistory
		}));
S
Sandeep Somavarapu 已提交
160
		this._register(attachInputBoxStyler(this.filterInputBox, this.themeService));
161
		this.filterInputBox.value = this.itemOptions.filterText;
S
Sandeep Somavarapu 已提交
162 163 164 165
		this._register(this.filterInputBox.onDidChange(filter => this.delayedFilterUpdate.trigger(() => this.onDidInputChange())));
		this._register(DOM.addStandardDisposableListener(this.filterInputBox.inputElement, 'keydown', (keyboardEvent) => this.onInputKeyDown(keyboardEvent, this.filterInputBox)));
		this._register(DOM.addStandardDisposableListener(container, 'keydown', this.handleKeyboardEvent));
		this._register(DOM.addStandardDisposableListener(container, 'keyup', this.handleKeyboardEvent));
166 167
	}

168 169 170 171 172 173
	private createControls(container: HTMLElement): void {
		this.controlsContainer = DOM.append(container, DOM.$('.markers-panel-filter-controls'));
		this.createBadge(this.controlsContainer);
		this.createFilesExcludeCheckbox(this.controlsContainer);
	}

S
Sandeep Somavarapu 已提交
174 175 176 177 178 179 180 181 182 183 184 185
	private createBadge(container: HTMLElement): void {
		this.filterBadge = DOM.append(container, DOM.$('.markers-panel-filter-badge'));
		this._register(attachStylerCallback(this.themeService, { badgeBackground, contrastBorder }, colors => {
			const background = colors.badgeBackground ? colors.badgeBackground.toString() : null;
			const border = colors.contrastBorder ? colors.contrastBorder.toString() : null;

			this.filterBadge.style.backgroundColor = background;

			this.filterBadge.style.borderWidth = border ? '1px' : null;
			this.filterBadge.style.borderStyle = border ? 'solid' : null;
			this.filterBadge.style.borderColor = border;
		}));
186
		this.updateBadge();
S
Sandeep Somavarapu 已提交
187
		this._register(this.markersWorkbenchService.onDidChange(() => this.updateBadge()));
S
Sandeep Somavarapu 已提交
188 189
	}

190 191 192 193 194 195 196 197 198 199 200 201 202 203
	private createFilesExcludeCheckbox(container: HTMLElement): void {
		this.filesExcludeFilter = new Checkbox({
			actionClassName: 'markers-panel-filter-filesExclude',
			title: this.itemOptions.useFilesExclude ? Messages.MARKERS_PANEL_ACTION_TOOLTIP_DO_NOT_USE_FILES_EXCLUDE : Messages.MARKERS_PANEL_ACTION_TOOLTIP_USE_FILES_EXCLUDE,
			isChecked: this.itemOptions.useFilesExclude,
			onChange: () => {
				this.filesExcludeFilter.domNode.title = this.filesExcludeFilter.checked ? Messages.MARKERS_PANEL_ACTION_TOOLTIP_DO_NOT_USE_FILES_EXCLUDE : Messages.MARKERS_PANEL_ACTION_TOOLTIP_USE_FILES_EXCLUDE;
				this._onDidChange.fire();
			}
		});
		this._register(attachCheckboxStyler(this.filesExcludeFilter, this.themeService));
		container.appendChild(this.filesExcludeFilter.domNode);
	}

S
Sandeep Somavarapu 已提交
204
	private onDidInputChange() {
205
		const filterText = this.filterInputBox.value;
206 207
		if (filterText) {
			this.filterInputBox.addToHistory(filterText);
S
Sandeep Somavarapu 已提交
208 209 210
		}
		this._onDidChange.fire();
		this.reportFilteringUsed();
211 212
	}

S
Sandeep Somavarapu 已提交
213 214
	private updateBadge(): void {
		const { total, filtered } = this.markersWorkbenchService.markersModel.stats();
215
		DOM.toggleClass(this.filterBadge, 'hidden', total === filtered || filtered === 0);
S
Sandeep Somavarapu 已提交
216
		this.filterBadge.textContent = localize('showing filtered problems', "Showing {0} of {1}", filtered, total);
217 218 219 220 221
		this.adjustInputBox();
	}

	private adjustInputBox(): void {
		this.filterInputBox.inputElement.style.paddingRight = (DOM.getTotalWidth(this.controlsContainer) || 20) + 'px';
222 223 224 225 226
	}

	// Action toolbar is swallowing some keys for action items which should not be for an input box
	private handleKeyboardEvent(e: IKeyboardEvent) {
		switch (e.keyCode) {
A
Alexandru Dima 已提交
227 228 229 230
			case KeyCode.Space:
			case KeyCode.LeftArrow:
			case KeyCode.RightArrow:
			case KeyCode.Escape:
231 232 233 234
				e.stopPropagation();
				break;
		}
	}
S
Sandeep Somavarapu 已提交
235

236
	private onInputKeyDown(keyboardEvent: IKeyboardEvent, filterInputBox: HistoryInputBox) {
S
Sandeep Somavarapu 已提交
237
		let handled = false;
S
Sandeep Somavarapu 已提交
238 239
		switch (keyboardEvent.keyCode) {
			case KeyCode.Escape:
J
Johannes Rieken 已提交
240
				filterInputBox.value = '';
S
Sandeep Somavarapu 已提交
241 242 243 244 245 246
				handled = true;
				break;
		}
		if (handled) {
			keyboardEvent.stopPropagation();
			keyboardEvent.preventDefault();
S
Sandeep Somavarapu 已提交
247 248
		}
	}
S
Sandeep Somavarapu 已提交
249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269

	private reportFilteringUsed(): void {
		let data = {};
		data['errors'] = this.markersWorkbenchService.markersModel.filterOptions.filterErrors;
		data['warnings'] = this.markersWorkbenchService.markersModel.filterOptions.filterWarnings;
		data['infos'] = this.markersWorkbenchService.markersModel.filterOptions.filterInfos;
		/* __GDPR__
			"problems.filter" : {
				"errors" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
				"warnings": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
				"infos": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }
			}
		*/
		this.telemetryService.publicLog('problems.filter', data);
	}

	private _register<T extends IDisposable>(t: T): T {
		this._toDispose.push(t);
		return t;
	}
}