Skip to content

Commit d778f61

Browse files
committed
#6679 Implement Markers tree view with file, count badge widgets. Show file on click or enter on marker
1 parent fe73dd1 commit d778f61

File tree

8 files changed

+247
-67
lines changed

8 files changed

+247
-67
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
/*---------------------------------------------------------------------------------------------
2+
* Copyright (c) Microsoft Corporation. All rights reserved.
3+
* Licensed under the MIT License. See License.txt in the project root for license information.
4+
*--------------------------------------------------------------------------------------------*/
5+
'use strict';
6+
7+
import * as nls from 'vs/nls';
8+
import winjs = require('vs/base/common/winjs.base');
9+
import lifecycle = require('vs/base/common/lifecycle');
10+
import actions = require('vs/base/common/actions');
11+
import actionbar = require('vs/base/browser/ui/actionbar/actionbar');
12+
import actionsrenderer = require('vs/base/parts/tree/browser/actionsRenderer');
13+
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
14+
import tree = require('vs/base/parts/tree/browser/tree');
15+
import { Resource } from 'vs/workbench/parts/markers/common/MarkersModel';
16+
17+
class RemoveResourceAction extends actions.Action {
18+
constructor() {
19+
super('remove', nls.localize('RemoveAction.label', "Remove"), 'action-remove');
20+
}
21+
22+
public run(context?: any): winjs.TPromise<any> {
23+
return (<tree.ITree>context['tree']).refresh();
24+
}
25+
}
26+
27+
export class ActionContainer implements lifecycle.IDisposable {
28+
29+
private cache: { [actionId:string]:actions.IAction; };
30+
private instantiationService: IInstantiationService;
31+
32+
constructor(instantiationService: IInstantiationService) {
33+
this.cache = <any> {};
34+
this.instantiationService = instantiationService;
35+
}
36+
37+
protected getAction(ctor: any, ...args: any[]): any {
38+
var action = this.cache[ctor.ID];
39+
40+
if (!action) {
41+
args.unshift(ctor);
42+
action = this.cache[ctor.ID] = this.instantiationService.createInstance.apply(this.instantiationService, args);
43+
}
44+
45+
return action;
46+
}
47+
48+
public dispose(): void {
49+
Object.keys(this.cache).forEach(k => {
50+
this.cache[k].dispose();
51+
});
52+
53+
this.cache = null;
54+
}
55+
}
56+
57+
58+
export class ActionProvider extends ActionContainer implements actionsrenderer.IActionProvider {
59+
60+
constructor(@IInstantiationService instantiationService: IInstantiationService) {
61+
super(instantiationService);
62+
}
63+
64+
public hasActions(tree: tree.ITree, element: any): boolean {
65+
return element instanceof Resource;
66+
}
67+
68+
public getActions(tree: tree.ITree, element: any): winjs.TPromise<actions.IAction[]> {
69+
return winjs.TPromise.as(this.getActionsForResource());
70+
}
71+
72+
public getActionsForResource(): actions.IAction[] {
73+
return [new RemoveResourceAction()];
74+
}
75+
76+
public hasSecondaryActions(tree: tree.ITree, element: any): boolean {
77+
return false;
78+
}
79+
80+
public getSecondaryActions(tree: tree.ITree, element: any): winjs.TPromise<actions.IAction[]> {
81+
return winjs.TPromise.as([]);
82+
}
83+
84+
public getActionItem(tree: tree.ITree, element: any, action: actions.IAction): actionbar.IActionItem {
85+
return null;
86+
}
87+
}

src/vs/workbench/parts/markers/browser/MarkersPanel.ts

+6-1
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,12 @@ import { Panel } from 'vs/workbench/browser/panel';
1414
import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService';
1515
import Constants from 'vs/workbench/parts/markers/common/Constants';
1616
import * as MarkersModel from 'vs/workbench/parts/markers/common/MarkersModel';
17+
import {Controller} from 'vs/workbench/parts/markers/browser/MarkersTreeController';
1718
import Tree = require('vs/base/parts/tree/browser/tree');
1819
import TreeImpl = require('vs/base/parts/tree/browser/treeImpl');
1920
import * as Viewer from 'vs/workbench/parts/markers/browser/MarkersTreeViewer';
2021
import {IInstantiationService} from 'vs/platform/instantiation/common/instantiation';
22+
import { ActionProvider } from 'vs/workbench/parts/markers/browser/MarkersActionProvider';
2123

2224
export class MarkersPanel extends Panel {
2325

@@ -38,10 +40,13 @@ export class MarkersPanel extends Panel {
3840
super.create(parent);
3941
dom.addClass(parent.getHTMLElement(), 'markers-panel');
4042

41-
var renderer = this.instantiationService.createInstance(Viewer.Renderer);
43+
var actionProvider = this.instantiationService.createInstance(ActionProvider);
44+
var renderer = this.instantiationService.createInstance(Viewer.Renderer, this.getActionRunner(), actionProvider);
45+
var controller = this.instantiationService.createInstance(Controller, actionProvider);
4246
this.tree = new TreeImpl.Tree(parent.getHTMLElement(), {
4347
dataSource: new Viewer.DataSource(),
4448
renderer: renderer,
49+
controller: controller
4550
}, {
4651
indentPixels: 0,
4752
twistiePixels: 20,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
/*---------------------------------------------------------------------------------------------
2+
* Copyright (c) Microsoft Corporation. All rights reserved.
3+
* Licensed under the MIT License. See License.txt in the project root for license information.
4+
*--------------------------------------------------------------------------------------------*/
5+
'use strict';
6+
7+
import * as errors from 'vs/base/common/errors';
8+
import mouse = require('vs/base/browser/mouseEvent');
9+
import keyboard = require('vs/base/browser/keyboardEvent');
10+
import actionsrenderer = require('vs/base/parts/tree/browser/actionsRenderer');
11+
import tree = require('vs/base/parts/tree/browser/tree');
12+
import treedefaults = require('vs/base/parts/tree/browser/treeDefaults');
13+
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
14+
import { CommonKeybindings } from 'vs/base/common/keyCodes';
15+
import { Marker } from 'vs/workbench/parts/markers/common/MarkersModel';
16+
import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService';
17+
import { IMarker } from 'vs/platform/markers/common/markers';
18+
19+
export class Controller extends treedefaults.DefaultController {
20+
21+
private contextMenuService:IContextMenuService;
22+
private actionProvider:actionsrenderer.IActionProvider;
23+
24+
constructor(actionProvider:actionsrenderer.IActionProvider,
25+
@IContextMenuService contextMenuService: IContextMenuService,
26+
@IWorkbenchEditorService private editorService: IWorkbenchEditorService) {
27+
super({ clickBehavior: treedefaults.ClickBehavior.ON_MOUSE_UP });
28+
29+
this.actionProvider = actionProvider;
30+
this.contextMenuService = contextMenuService;
31+
32+
this.downKeyBindingDispatcher.set(CommonKeybindings.SHIFT_UP_ARROW, this.onUp.bind(this));
33+
this.downKeyBindingDispatcher.set(CommonKeybindings.SHIFT_DOWN_ARROW, this.onDown.bind(this));
34+
this.downKeyBindingDispatcher.set(CommonKeybindings.SHIFT_PAGE_UP, this.onPageUp.bind(this));
35+
this.downKeyBindingDispatcher.set(CommonKeybindings.SHIFT_PAGE_DOWN, this.onPageDown.bind(this));
36+
}
37+
38+
protected onLeftClick(tree: tree.ITree, element: any, event: mouse.IMouseEvent): boolean {
39+
if (this.openFileAtElement(element)) {
40+
return true;
41+
}
42+
return super.onLeftClick(tree, element, event);
43+
}
44+
45+
protected onEnter(tree:tree.ITree, event:keyboard.IKeyboardEvent):boolean {
46+
super.onEnter(tree, event);
47+
this.openFileAtElement(tree.getFocus());
48+
return true;
49+
}
50+
51+
private openFileAtElement(element: any) {
52+
if (element instanceof Marker) {
53+
let marker= <IMarker>element.marker;
54+
this.editorService.openEditor({
55+
resource: marker.resource,
56+
options: {
57+
selection: {
58+
startLineNumber: marker.startLineNumber,
59+
startColumn: marker.startColumn,
60+
endLineNumber: marker.endLineNumber,
61+
endColumn: marker.endColumn
62+
}
63+
}
64+
}).done(null, errors.onUnexpectedError);
65+
return true;
66+
}
67+
return false;
68+
}
69+
}

src/vs/workbench/parts/markers/browser/MarkersTreeViewer.ts

+50-36
Original file line numberDiff line numberDiff line change
@@ -4,29 +4,32 @@
44
*--------------------------------------------------------------------------------------------*/
55
'use strict';
66

7-
import * as winjs from 'vs/base/common/winjs.base';
8-
import * as paths from 'vs/base/common/paths';
9-
import dom = require('vs/base/browser/dom');
10-
import { IMarker } from 'vs/platform/markers/common/markers';
11-
import tree = require('vs/base/parts/tree/browser/tree');
12-
import { Marker, Resource } from 'vs/workbench/parts/markers/common/MarkersModel';
7+
import {TPromise, Promise} from 'vs/base/common/winjs.base';
8+
import * as dom from 'vs/base/browser/dom';
9+
import {IDataSource, ITree, IRenderer} from 'vs/base/parts/tree/browser/tree';
10+
import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar';
11+
import { IActionRunner } from 'vs/base/common/actions';
1312
import Severity from 'vs/base/common/severity';
1413
import {IWorkspaceContextService} from 'vs/workbench/services/workspace/common/contextService';
15-
import { getPathLabel } from 'vs/base/common/labels';
16-
17-
var $ = dom.emmet;
14+
import { ActionProvider } from 'vs/workbench/parts/markers/browser/MarkersActionProvider';
15+
import { CountBadge } from 'vs/base/browser/ui/countBadge/countBadge';
16+
import { FileLabel } from 'vs/base/browser/ui/fileLabel/fileLabel';
17+
import { IMarker } from 'vs/platform/markers/common/markers';
18+
import { Marker, Resource } from 'vs/workbench/parts/markers/common/MarkersModel';
1819

1920
interface IResourceTemplateData {
20-
label: HTMLElement;
21+
file: FileLabel;
22+
count: CountBadge;
23+
actionBar: ActionBar;
2124
}
2225

2326
interface IMarkerTemplateData {
2427
icon: HTMLElement;
2528
label: HTMLElement;
2629
}
2730

28-
export class DataSource implements tree.IDataSource {
29-
public getId(tree: tree.ITree, element: any): string {
31+
export class DataSource implements IDataSource {
32+
public getId(tree: ITree, element: any): string {
3033
if (element instanceof Resource) {
3134
return 'resource' + (<Resource>element).uri.toString();
3235
}
@@ -36,39 +39,42 @@ export class DataSource implements tree.IDataSource {
3639
return 'root';
3740
}
3841

39-
public hasChildren(tree: tree.ITree, element: any): boolean {
42+
public hasChildren(tree: ITree, element: any): boolean {
4043
return !(element instanceof Marker);
4144
}
4245

43-
public getChildren(tree: tree.ITree, element: any): winjs.Promise {
46+
public getChildren(tree: ITree, element: any): Promise {
4447
if (element instanceof Resource) {
45-
return winjs.TPromise.as((<Resource>element).markers);
48+
return TPromise.as((<Resource>element).markers);
4649
}
47-
return winjs.TPromise.as(element['resources']);
50+
return TPromise.as(element['resources']);
4851
}
4952

50-
public getParent(tree: tree.ITree, element: any): winjs.Promise {
51-
return winjs.TPromise.as(null);
53+
public getParent(tree: ITree, element: any): Promise {
54+
return TPromise.as(null);
5255
}
5356
}
5457

55-
export class Renderer implements tree.IRenderer {
56-
constructor(@IWorkspaceContextService private contextService: IWorkspaceContextService
58+
export class Renderer implements IRenderer {
59+
60+
constructor(private actionRunner: IActionRunner,
61+
private actionProvider:ActionProvider,
62+
@IWorkspaceContextService private contextService: IWorkspaceContextService
5763
) {
5864
}
5965

60-
public getHeight(tree:tree.ITree, element:any): number {
66+
public getHeight(tree:ITree, element:any): number {
6167
return 22;
6268
}
6369

64-
public getTemplateId(tree:tree.ITree, element:any): string {
70+
public getTemplateId(tree:ITree, element:any): string {
6571
if (element instanceof Resource) {
6672
return 'resource';
6773
}
6874
return 'marker';
6975
}
7076

71-
public renderTemplate(tree: tree.ITree, templateId: string, container: HTMLElement): any {
77+
public renderTemplate(tree: ITree, templateId: string, container: HTMLElement): any {
7278
if ('resource' === templateId) {
7379
return this.renderResourceTemplate(container);
7480
} else {
@@ -78,36 +84,41 @@ export class Renderer implements tree.IRenderer {
7884

7985
private renderResourceTemplate(container: HTMLElement): IResourceTemplateData {
8086
var data: IResourceTemplateData = Object.create(null);
81-
data.label = dom.append(container, $('.label'));
87+
data.file = new FileLabel(container, null, this.contextService);
88+
89+
const badgeWrapper = dom.append(container, dom.emmet('.count-badge-wrapper'));
90+
data.count = new CountBadge(badgeWrapper);
91+
92+
data.actionBar = new ActionBar(container, { actionRunner: this.actionRunner });
93+
data.actionBar.push(this.actionProvider.getActionsForResource(), { icon: true, label: false });
8294
return data;
8395
}
8496

8597
private renderMarkerTemplate(container: HTMLElement): IMarkerTemplateData {
8698
var data: IMarkerTemplateData = Object.create(null);
87-
data.icon = dom.append(container, $('.marker-icon'));
88-
data.label = dom.append(container, $('span.label'));
99+
data.icon = dom.append(container, dom.emmet('.marker-icon'));
100+
data.label = dom.append(container, dom.emmet('span.label'));
89101
return data;
90102
}
91103

92-
public renderElement(tree: tree.ITree, element: any, templateId: string, templateData: any): void {
104+
public renderElement(tree: ITree, element: any, templateId: string, templateData: any): void {
93105
if ('resource' === templateId) {
94106
return this.renderResourceElement(tree, <Resource> element, templateData);
95107
} else {
96108
return this.renderMarkerElement(tree, (<Marker>element).marker, templateData);
97109
}
98110
}
99111

100-
public disposeTemplate(tree: tree.ITree, templateId: string, templateData: any): void {
101-
}
102-
103-
private renderResourceElement(tree: tree.ITree, element: Resource, templateData: IResourceTemplateData) {
104-
let fileNameElement= dom.append(templateData.label, $('span.file-name'));
105-
fileNameElement.textContent= paths.basename(element.uri.fsPath);
106-
let fileLocationElement= dom.append(templateData.label, $('span.file-path'));
107-
fileLocationElement.textContent= getPathLabel(element.uri, this.contextService);
112+
private renderResourceElement(tree: ITree, element: Resource, templateData: IResourceTemplateData) {
113+
templateData.file.setValue(element.uri);
114+
templateData.count.setCount(10);
115+
templateData.actionBar.context= {
116+
tree: tree,
117+
element: element
118+
};
108119
}
109120

110-
private renderMarkerElement(tree: tree.ITree, element: IMarker, templateData: IMarkerTemplateData) {
121+
private renderMarkerElement(tree: ITree, element: IMarker, templateData: IMarkerTemplateData) {
111122
templateData.icon.className = 'icon ' + Renderer.iconClassNameFor(element);
112123
templateData.label.textContent = element.message;
113124
}
@@ -125,4 +136,7 @@ export class Renderer implements tree.IRenderer {
125136
}
126137
return '';
127138
}
139+
140+
public disposeTemplate(tree: ITree, templateId: string, templateData: any): void {
141+
}
128142
}
Loading
Loading

0 commit comments

Comments
 (0)