markersPanelActions.ts 10.1 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 { InputBox } 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';
S
Sandeep Somavarapu 已提交
23
import { attachInputBoxStyler, attachStylerCallback } from 'vs/platform/theme/common/styler';
24
import { IMarkersWorkbenchService } from 'vs/workbench/parts/markers/electron-browser/markers';
S
Sandeep Somavarapu 已提交
25 26 27 28 29 30
import { Event, Emitter } from 'vs/base/common/event';
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
import { HistoryNavigator } from 'vs/base/common/history';
import { BaseActionItem } from 'vs/base/browser/ui/actionbar/actionbar';
import { badgeBackground, contrastBorder } from 'vs/platform/theme/common/colorRegistry';
import { localize } from '../../../../nls';
31

32
export class ToggleMarkersPanelAction extends TogglePanelAction {
33

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

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

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

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

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

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

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

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

S
Sandeep Somavarapu 已提交
70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97
export class FilterByFilesExcludeAction extends Action {

	public static readonly ID: string = 'workbench.actions.problems.useFilesExclude';

	private readonly _onDidCheck: Emitter<boolean> = new Emitter<boolean>();
	readonly onDidCheck: Event<boolean> = this._onDidCheck.event;

	private toDispose: IDisposable[] = [];

	constructor(checked: boolean) {
		super(FilterByFilesExcludeAction.ID, checked ? Messages.MARKERS_PANEL_ACTION_TOOLTIP_DO_NOT_USE_FILES_EXCLUDE : Messages.MARKERS_PANEL_ACTION_TOOLTIP_USE_FILES_EXCLUDE, 'markers-panel-action-files-exclude', true);
		this.toDispose.push(this._onDidCheck);
		this.checked = checked;
	}

	public run(): TPromise<any> {
		this.checked = !this.checked;
		this.tooltip = this.checked ? Messages.MARKERS_PANEL_ACTION_TOOLTIP_DO_NOT_USE_FILES_EXCLUDE : Messages.MARKERS_PANEL_ACTION_TOOLTIP_USE_FILES_EXCLUDE;
		this._onDidCheck.fire(this.checked);
		return TPromise.as(null);
	}

	dispose(): void {
		this.toDispose = dispose(this.toDispose);
		super.dispose();
	}
}

98 99
export class FilterAction extends Action {

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

S
Sandeep Somavarapu 已提交
102
	constructor() {
S
Sandeep Somavarapu 已提交
103
		super(FilterAction.ID, Messages.MARKERS_PANEL_ACTION_TOOLTIP_FILTER, 'markers-panel-action-filter', true);
104 105 106 107 108
	}

}


S
Sandeep Somavarapu 已提交
109 110 111 112 113 114
export class FilterInputActionItem extends BaseActionItem {

	private _toDispose: IDisposable[] = [];

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

116
	private delayedFilterUpdate: Delayer<void>;
S
Sandeep Somavarapu 已提交
117 118 119 120
	private container: HTMLElement;
	private filterInputBox: InputBox;
	private filterHistory: HistoryNavigator<string>;
	private filterBadge: HTMLInputElement;
121

S
Sandeep Somavarapu 已提交
122 123 124 125
	constructor(
		private filterText: string,
		filterHistory: string[],
		action: IAction,
J
Johannes Rieken 已提交
126
		@IContextViewService private contextViewService: IContextViewService,
B
Benjamin Pasero 已提交
127
		@IThemeService private themeService: IThemeService,
S
Sandeep Somavarapu 已提交
128
		@IMarkersWorkbenchService private markersWorkbenchService: IMarkersWorkbenchService,
S
Sandeep Somavarapu 已提交
129 130 131
		@ITelemetryService private telemetryService: ITelemetryService
	) {
		super(null, action);
J
Johannes Rieken 已提交
132
		this.delayedFilterUpdate = new Delayer<void>(500);
S
Sandeep Somavarapu 已提交
133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148
		this.filterHistory = new HistoryNavigator<string>(filterHistory);
	}

	render(container: HTMLElement): void {
		this.container = container;
		DOM.addClass(this.container, 'markers-panel-action-filter');
		this.createInput(this.container);
		this.createBadge(this.container);
	}

	getFilterText(): string {
		return this.filterText;
	}

	getFilterHistory(): string[] {
		return this.filterHistory.getHistory();
149 150
	}

S
Sandeep Somavarapu 已提交
151 152 153 154 155 156 157 158 159
	toggleLayout(small: boolean) {
		if (this.container) {
			DOM.toggleClass(this.container, 'small', small);
			DOM.toggleClass(this.filterBadge, 'small', small);
		}
	}

	private createInput(container: HTMLElement): void {
		this.filterInputBox = new InputBox(container, this.contextViewService, {
160
			placeholder: Messages.MARKERS_PANEL_FILTER_PLACEHOLDER,
S
Sandeep Somavarapu 已提交
161
			ariaLabel: Messages.MARKERS_PANEL_FILTER_ARIA_LABEL
162
		});
S
Sandeep Somavarapu 已提交
163 164 165 166 167 168
		this._register(attachInputBoxStyler(this.filterInputBox, this.themeService));
		this.filterInputBox.value = this.filterText;
		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));
169 170
	}

S
Sandeep Somavarapu 已提交
171 172 173 174 175 176 177 178 179 180 181 182 183
	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;
		}));
		this._register(this.markersWorkbenchService.onDidChange(() => this.updateBadge()));
S
Sandeep Somavarapu 已提交
184 185
	}

S
Sandeep Somavarapu 已提交
186 187 188 189 190 191 192
	private onDidInputChange() {
		this.filterText = this.filterInputBox.value;
		if (this.filterText && this.filterText !== this.filterHistory.current()) {
			this.filterHistory.add(this.getFilterText());
		}
		this._onDidChange.fire();
		this.reportFilteringUsed();
193 194
	}

S
Sandeep Somavarapu 已提交
195 196 197 198 199
	private updateBadge(): void {
		const { total, filtered } = this.markersWorkbenchService.markersModel.stats();
		DOM.toggleClass(this.filterBadge, 'hidden', total === filtered);
		this.filterBadge.textContent = localize('showing filtered problems', "Showing {0} of {1}", filtered, total);
		this.filterInputBox.inputElement.style.paddingRight = DOM.getTotalWidth(this.filterBadge) + 'px';
200 201 202 203 204
	}

	// 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 已提交
205 206 207 208
			case KeyCode.Space:
			case KeyCode.LeftArrow:
			case KeyCode.RightArrow:
			case KeyCode.Escape:
209 210 211 212
				e.stopPropagation();
				break;
		}
	}
S
Sandeep Somavarapu 已提交
213

S
Sandeep Somavarapu 已提交
214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232
	private showNextFilter() {
		let next = this.filterHistory.next();
		if (next) {
			this.filterInputBox.value = next;
		}
	}

	private showPreviousFilter() {
		let previous = this.filterHistory.previous();
		if (this.filterInputBox.value) {
			this.filterHistory.addIfNotPresent(this.filterInputBox.value);
		}
		if (previous) {
			this.filterInputBox.value = previous;
		}
	}

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

	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;
	}
}