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

import 'vs/css!./media/markers';
S
Sandeep Somavarapu 已提交
7

S
Sandeep Somavarapu 已提交
8 9
import * as errors from 'vs/base/common/errors';
import * as Set from 'vs/base/common/set';
S
Sandeep Somavarapu 已提交
10
import URI from 'vs/base/common/uri';
11
import { TPromise } from 'vs/base/common/winjs.base';
S
Sandeep Somavarapu 已提交
12
import { Delayer } from 'vs/base/common/async';
13
import dom = require('vs/base/browser/dom');
14 15
import lifecycle = require('vs/base/common/lifecycle');
import builder = require('vs/base/browser/builder');
S
Sandeep Somavarapu 已提交
16
import {Action} from 'vs/base/common/actions';
17
import {IActionItem} from 'vs/base/browser/ui/actionbar/actionbar';
18 19
import { IMarkerService } from 'vs/platform/markers/common/markers';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
20
import { IEventService } from 'vs/platform/event/common/event';
S
Sandeep Somavarapu 已提交
21 22
import { IEditorGroupService } from 'vs/workbench/services/group/common/groupService';
import { FileEditorInput } from 'vs/workbench/parts/files/browser/editors/fileEditorInput';
23
import { Panel } from 'vs/workbench/browser/panel';
S
Sandeep Somavarapu 已提交
24
import { IAction } from 'vs/base/common/actions';
25
import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService';
26
import Constants from 'vs/workbench/parts/markers/common/constants';
27
import { IProblemsConfiguration, MarkersModel, Marker, Resource } from 'vs/workbench/parts/markers/common/markersModel';
28
import {Controller} from 'vs/workbench/parts/markers/browser/markersTreeController';
29 30
import Tree = require('vs/base/parts/tree/browser/tree');
import TreeImpl = require('vs/base/parts/tree/browser/treeImpl');
31
import * as Viewer from 'vs/workbench/parts/markers/browser/markersTreeViewer';
S
Sandeep Somavarapu 已提交
32
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
33
import { ActionProvider } from 'vs/workbench/parts/markers/browser/markersActionProvider';
S
Sandeep Somavarapu 已提交
34
import { CollapseAllAction, FilterAction, FilterInputBoxActionItem } from 'vs/workbench/parts/markers/browser/markersPanelActions';
S
Sandeep Somavarapu 已提交
35
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
36 37 38

export class MarkersPanel extends Panel {

39
	public markersModel: MarkersModel;
40

S
Sandeep Somavarapu 已提交
41
	private toDispose: lifecycle.IDisposable[];
S
Sandeep Somavarapu 已提交
42 43
	private delayedRefresh: Delayer<void>;

44
	private lastSelectedRelativeTop: number= 0;
S
Sandeep Somavarapu 已提交
45 46 47
	private currentActiveFile: URI = null;
	private hasToAutoReveal: boolean;

S
Sandeep Somavarapu 已提交
48
	private tree: Tree.ITree;
49
	private autoExpanded: Set.ArraySet<string>;
50

S
Sandeep Somavarapu 已提交
51
	private actions: IAction[];
52
	private filterAction: FilterAction;
S
Sandeep Somavarapu 已提交
53 54
	private collapseAllAction: IAction;

S
Sandeep Somavarapu 已提交
55
	private treeContainer: HTMLElement;
S
Sandeep Somavarapu 已提交
56 57 58
	private messageBoxContainer: HTMLElement;
	private messageBox: HTMLElement;

59 60 61
	constructor(
		@IInstantiationService private instantiationService: IInstantiationService,
		@IMarkerService private markerService: IMarkerService,
S
Sandeep Somavarapu 已提交
62
		@IEditorGroupService private editorGroupService: IEditorGroupService,
63
		@IWorkbenchEditorService private editorService: IWorkbenchEditorService,
64
		@IEventService private eventService: IEventService,
S
Sandeep Somavarapu 已提交
65
		@IConfigurationService private configurationService: IConfigurationService,
66 67 68
		@ITelemetryService telemetryService: ITelemetryService
	) {
		super(Constants.MARKERS_PANEL_ID, telemetryService);
S
Sandeep Somavarapu 已提交
69
		this.markersModel = new MarkersModel();
S
Sandeep Somavarapu 已提交
70
		this.toDispose = [];
S
Sandeep Somavarapu 已提交
71 72
		this.delayedRefresh = new Delayer<void>(1000);
		this.autoExpanded = new Set.ArraySet<string>();
73 74 75 76
	}

	public create(parent: builder.Builder): TPromise<void> {
		super.create(parent);
77
		dom.addClass(parent.getHTMLElement(), 'markers-panel');
78

S
Sandeep Somavarapu 已提交
79 80 81 82
		const conf = this.configurationService.getConfiguration<IProblemsConfiguration>();
		this.onConfigurationsUpdated(conf);

		let container = dom.append(parent.getHTMLElement(), dom.emmet('.markers-panel-container'));
S
Sandeep Somavarapu 已提交
83

84
		this.createMessageBox(container);
S
Sandeep Somavarapu 已提交
85 86
		this.createTree(container);

S
Sandeep Somavarapu 已提交
87
		this.createActions();
88
		this.createListeners();
89 90

		this.render();
S
Sandeep Somavarapu 已提交
91

92 93 94
		return TPromise.as(null);
	}

S
Sandeep Somavarapu 已提交
95 96
	public getTitle(): string {
		let markerStatistics = this.markerService.getStatistics();
S
Sandeep Somavarapu 已提交
97
		return this.markersModel.getTitle(markerStatistics);
S
Sandeep Somavarapu 已提交
98 99
	}

100 101 102 103
	public layout(dimension: builder.Dimension): void {
		this.tree.layout(dimension.height);
	}

S
Sandeep Somavarapu 已提交
104
	public focus(): void {
105 106 107 108
		if (this.tree.isDOMFocused()) {
			return;
		}

S
Sandeep Somavarapu 已提交
109
		if (this.markersModel.hasFilteredResources()) {
110
			this.tree.DOMFocus();
S
Sandeep Somavarapu 已提交
111 112 113 114
			if (this.tree.getSelection().length === 0) {
				this.tree.focusFirst();
			}
			this.autoReveal(true);
S
Sandeep Somavarapu 已提交
115 116
		} else {
			this.messageBox.focus();
S
Sandeep Somavarapu 已提交
117
		}
S
Sandeep Somavarapu 已提交
118 119 120
	}

	public getActions(): IAction[] {
S
Sandeep Somavarapu 已提交
121
		this.collapseAllAction.enabled = this.markersModel.hasFilteredResources();
S
Sandeep Somavarapu 已提交
122 123 124
		return this.actions;
	}

S
Sandeep Somavarapu 已提交
125 126
	public refreshPanel(updateTitleArea: boolean = false): TPromise<any> {
		this.collapseAllAction.enabled = this.markersModel.hasFilteredResources();
127 128 129 130
		this.refreshAutoExpanded();
		if (updateTitleArea) {
			this.updateTitleArea();
		}
S
Sandeep Somavarapu 已提交
131 132 133 134 135 136 137 138
		dom.toggleClass(this.treeContainer, 'hidden', !this.markersModel.hasFilteredResources());
		this.renderMessage();
		if (this.markersModel.hasFilteredResources()) {
			return this.tree.refresh().then(() => {
				this.autoExpand();
			});
		}
		return TPromise.as(null);
139 140
	}

S
Sandeep Somavarapu 已提交
141
	private createMessageBox(parent: HTMLElement): void {
S
Sandeep Somavarapu 已提交
142
		this.messageBoxContainer = dom.append(parent, dom.emmet('.message-box-container'));
S
Sandeep Somavarapu 已提交
143 144
		this.messageBox = dom.append(this.messageBoxContainer, dom.emmet('span'));
		this.messageBox.setAttribute('tabindex', '0');
S
Sandeep Somavarapu 已提交
145 146
	}

S
Sandeep Somavarapu 已提交
147 148
	private createTree(parent: HTMLElement): void {
		this.treeContainer = dom.append(parent, dom.emmet('.tree-container'));
S
Sandeep Somavarapu 已提交
149 150 151
		var actionProvider = this.instantiationService.createInstance(ActionProvider);
		var renderer = this.instantiationService.createInstance(Viewer.Renderer, this.getActionRunner(), actionProvider);
		var controller = this.instantiationService.createInstance(Controller);
S
Sandeep Somavarapu 已提交
152
		this.tree = new TreeImpl.Tree(this.treeContainer, {
S
Sandeep Somavarapu 已提交
153 154
			dataSource: new Viewer.DataSource(),
			renderer: renderer,
S
Sandeep Somavarapu 已提交
155 156
			controller: controller,
			accessibilityProvider: new Viewer.ProblemsTreeAccessibilityProvider()
S
Sandeep Somavarapu 已提交
157
		}, {
S
Sandeep Somavarapu 已提交
158 159 160
				indentPixels: 0,
				twistiePixels: 20,
			});
S
Sandeep Somavarapu 已提交
161 162
	}

S
Sandeep Somavarapu 已提交
163 164 165 166 167 168 169
	private createActions(): void {
		this.collapseAllAction = this.instantiationService.createInstance(CollapseAllAction, this.tree, true);
		this.filterAction = new FilterAction(this);
		this.actions = [
			this.filterAction,
			this.collapseAllAction
		];
S
Sandeep Somavarapu 已提交
170 171 172 173 174
		this.actions.forEach(a => {
			this.toDispose.push(a);
		});
	}

175
	private createListeners(): void {
S
Sandeep Somavarapu 已提交
176 177 178
		this.toDispose.push(this.configurationService.onDidUpdateConfiguration(e => this.onConfigurationsUpdated(e.config)));
		this.toDispose.push(this.markerService.onMarkerChanged(this.onMarkerChanged, this));
		this.toDispose.push(this.editorGroupService.onEditorsChanged(this.onEditorsChanged, this));
179
		this.toDispose.push(this.tree.addListener2('selection', () => this.onSelected()));
180 181
	}

S
Sandeep Somavarapu 已提交
182 183
	private onMarkerChanged(changedResources: URI[]) {
		this.updateResources(changedResources);
S
Sandeep Somavarapu 已提交
184
		// this.delayedRefresh.trigger(() => {this.refreshPanel(true);});
185
		this.refreshPanel(true);
S
Sandeep Somavarapu 已提交
186 187 188 189 190 191 192 193 194 195 196
		this.autoReveal();
	}

	private onEditorsChanged(): void {
		let activeInput = this.editorService.getActiveEditorInput();
		this.currentActiveFile = activeInput instanceof FileEditorInput ? activeInput.getResource() : null;
		this.autoReveal();
	}

	private onConfigurationsUpdated(conf: IProblemsConfiguration): void {
		this.hasToAutoReveal = conf && conf.problems && conf.problems.autoReveal;
197 198
	}

199 200 201 202 203 204 205
	private onSelected(): void {
		let selection= this.tree.getSelection();
		if (selection && selection.length > 0) {
			this.lastSelectedRelativeTop= this.tree.getRelativeTop(selection[0]);
		}
	}

S
Sandeep Somavarapu 已提交
206 207
	private updateResources(resources: URI[]) {
		resources.forEach((resource) => {
S
Sandeep Somavarapu 已提交
208
			let markers = this.markerService.read({ resource: resource }).slice(0);
209 210 211 212
			this.markersModel.update(resource, markers);
			if (!this.markersModel.hasResource(resource)) {
				this.autoExpanded.unset(resource.toString());
			}
S
Sandeep Somavarapu 已提交
213
		});
S
Sandeep Somavarapu 已提交
214 215
	}

216 217
	private render(): void {
		let allMarkers = this.markerService.read().slice(0);
218
		this.markersModel.update(allMarkers);
S
Sandeep Somavarapu 已提交
219
		this.tree.setInput(this.markersModel).then(this.autoExpand.bind(this));
S
Sandeep Somavarapu 已提交
220
		dom.toggleClass(this.treeContainer, 'hidden', !this.markersModel.hasFilteredResources());
S
Sandeep Somavarapu 已提交
221 222 223
		this.renderMessage();
	}

S
Sandeep Somavarapu 已提交
224 225 226
	private renderMessage(): void {
		let message = this.markersModel.getMessage();
		this.messageBox.textContent = message;
S
Sandeep Somavarapu 已提交
227
		dom.toggleClass(this.messageBoxContainer, 'hidden', this.markersModel.hasFilteredResources());
S
Sandeep Somavarapu 已提交
228 229
	}

230 231 232 233 234 235 236 237
	private refreshAutoExpanded(): void {
		this.markersModel.nonFilteredResources.forEach((resource) => {
			if (this.tree.isExpanded(resource)) {
				this.autoExpanded.unset(resource.uri.toString());
			}
		});
	}

S
Sandeep Somavarapu 已提交
238
	private autoExpand(): void {
239 240
		this.markersModel.filteredResources.forEach((resource) => {
			if (this.autoExpanded.contains(resource.uri.toString())) {
S
Sandeep Somavarapu 已提交
241 242
				return;
			}
243
			this.tree.expand(resource).done(null, errors.onUnexpectedError);
244
			this.autoExpanded.set(resource.uri.toString());
S
Sandeep Somavarapu 已提交
245
		});
246 247
	}

S
Sandeep Somavarapu 已提交
248
	private autoReveal(focus: boolean= false): void {
S
Sandeep Somavarapu 已提交
249 250
		let conf = this.configurationService.getConfiguration<IProblemsConfiguration>();
		if (conf && conf.problems && conf.problems.autoReveal) {
S
Sandeep Somavarapu 已提交
251
			this.revealProblemsForCurrentActiveEditor(focus);
252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269
		}
	}

	private revealProblemsForCurrentActiveEditor(focus: boolean= false): void {
		let currentActiveResource = this.getResourceForCurrentActiveFile();
		if (currentActiveResource) {
			if (this.tree.isExpanded(currentActiveResource) && this.hasSelectedMarkerFor(currentActiveResource)) {
				this.tree.reveal(this.tree.getSelection()[0], this.lastSelectedRelativeTop);
				if (focus) {
					this.tree.setFocus(this.tree.getSelection()[0]);
				}
			} else {
				this.tree.reveal(currentActiveResource, 0);
				if (focus) {
					this.tree.setFocus(currentActiveResource);
					this.tree.setSelection([currentActiveResource]);
				}
			}
S
Sandeep Somavarapu 已提交
270 271 272
		} else if (focus) {
			this.tree.setSelection([]);
			this.tree.focusFirst();
273 274 275 276 277
		}
	}

	private getResourceForCurrentActiveFile(): Resource {
		if (this.currentActiveFile) {
S
Sandeep Somavarapu 已提交
278 279 280
			let resources = this.markersModel.filteredResources.filter((resource): boolean => {
				return this.currentActiveFile.toString() === resource.uri.toString();
			});
281
			return resources.length > 0 ? resources[0] : null;
S
Sandeep Somavarapu 已提交
282
		}
283
		return null;
S
Sandeep Somavarapu 已提交
284 285 286 287 288 289 290 291 292 293 294 295 296 297
	}

	private hasSelectedMarkerFor(resource): boolean {
		let selectedElement = this.tree.getSelection();
		if (selectedElement && selectedElement.length > 0) {
			if (selectedElement[0] instanceof Marker) {
				if (resource.uri.toString() === selectedElement[0].marker.resource.toString()) {
					return true;
				}
			}
		}
		return false;
	}

298
	public getActionItem(action: Action): IActionItem {
S
Sandeep Somavarapu 已提交
299
		if (action.id === FilterAction.ID) {
300 301 302
			return this.instantiationService.createInstance(FilterInputBoxActionItem, this, action);
		}
		return super.getActionItem(action);
S
Sandeep Somavarapu 已提交
303 304
	}

305
	public dispose(): void {
S
Sandeep Somavarapu 已提交
306
		this.delayedRefresh.cancel();
S
Sandeep Somavarapu 已提交
307
		this.toDispose = lifecycle.dispose(this.toDispose);
308 309 310
		super.dispose();
	}
}