提交 2570a185 编写于 作者: J Joao Moreno

wip: problems tree

上级 7843e40d
......@@ -8,12 +8,13 @@ import { IDisposable, dispose } from 'vs/base/common/lifecycle';
import { IListOptions, List, IIdentityProvider, IMultipleSelectionController } from 'vs/base/browser/ui/list/listWidget';
import { IVirtualDelegate, IRenderer, IListMouseEvent } from 'vs/base/browser/ui/list/list';
import { append, $ } from 'vs/base/browser/dom';
import { Event, Relay, chain } from 'vs/base/common/event';
import { Event, Relay, chain, mapEvent } from 'vs/base/common/event';
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
import { KeyCode } from 'vs/base/common/keyCodes';
import { ITreeModel, ITreeNode } from 'vs/base/browser/ui/tree/tree';
import { ISpliceable } from 'vs/base/common/sequence';
import { IIndexTreeModelOptions } from 'vs/base/browser/ui/tree/indexTreeModel';
import { memoize } from 'vs/base/common/decorators';
export function createComposedTreeListOptions<T, N extends { element: T }>(options?: IListOptions<T>): IListOptions<N> {
if (!options) {
......@@ -174,6 +175,14 @@ export abstract class AbstractTree<T, TFilterData, TRef> implements IDisposable
readonly onDidChangeCollapseState: Event<ITreeNode<T, TFilterData>>;
@memoize get onDidChangeFocus(): Event<T[]> {
return mapEvent(this.view.onFocusChange, e => e.elements.map(e => e.element));
}
@memoize get onDidChangeSelection(): Event<T[]> {
return mapEvent(this.view.onSelectionChange, e => e.elements.map(e => e.element));
}
constructor(
container: HTMLElement,
delegate: IVirtualDelegate<T>,
......@@ -202,10 +211,13 @@ export abstract class AbstractTree<T, TFilterData, TRef> implements IDisposable
onKeyDown.filter(e => e.keyCode === KeyCode.Space).on(this.onSpace, this, this.disposables);
}
protected abstract createModel(view: ISpliceable<ITreeNode<T, TFilterData>>, options: ITreeOptions<T, TFilterData>): ITreeModel<T, TFilterData, TRef>;
// TODO@joao rename to `get domElement`
getHTMLElement(): HTMLElement {
return this.view.getHTMLElement();
}
refilter(): void {
this.model.refilter();
layout(height?: number): void {
this.view.layout(height);
}
collapse(location: TRef): boolean {
......@@ -216,6 +228,88 @@ export abstract class AbstractTree<T, TFilterData, TRef> implements IDisposable
return this.model.setCollapsed(location, false);
}
toggleCollapsed(ref: TRef): void {
this.model.toggleCollapsed(ref);
}
isCollapsed(ref: TRef): boolean {
return this.model.isCollapsed(ref);
}
isExpanded(ref: TRef): boolean {
return !this.isCollapsed(ref);
}
refilter(): void {
this.model.refilter();
}
setSelection(elements: TRef[]): void {
const indexes = elements.map(e => this.model.getListIndex(e));
this.view.setSelection(indexes);
}
selectNext(n = 1, loop = false): void {
this.view.selectNext(n, loop);
}
selectPrevious(n = 1, loop = false): void {
this.view.selectPrevious(n, loop);
}
getSelection(): T[] {
const nodes = this.view.getSelectedElements();
return nodes.map(n => n.element);
}
setFocus(elements: TRef[]): void {
const indexes = elements.map(e => this.model.getListIndex(e));
this.view.setFocus(indexes);
}
focusNext(n = 1, loop = false): void {
this.view.focusNext();
}
focusPrevious(n = 1, loop = false): void {
this.view.focusPrevious();
}
focusNextPage(): void {
this.view.focusNextPage();
}
focusPreviousPage(): void {
this.view.focusPreviousPage();
}
focusLast(): void {
this.view.focusLast();
}
focusFirst(): void {
this.view.focusFirst();
}
getFocus(): T[] {
const nodes = this.view.getFocusedElements();
return nodes.map(n => n.element);
}
reveal(location: TRef, relativeTop?: number): void {
const index = this.model.getListIndex(location);
this.view.reveal(index, relativeTop);
}
/**
* Returns the relative position of an element rendered in the list.
* Returns `null` if the element isn't *entirely* in the visible viewport.
*/
getRelativeTop(location: TRef): number | null {
const index = this.model.getListIndex(location);
return this.view.getRelativeTop(index);
}
private onMouseClick(e: IListMouseEvent<ITreeNode<T, TFilterData>>): void {
const node = e.element;
const location = this.model.getNodeLocation(node);
......@@ -293,6 +387,8 @@ export abstract class AbstractTree<T, TFilterData, TRef> implements IDisposable
this.model.toggleCollapsed(location);
}
protected abstract createModel(view: ISpliceable<ITreeNode<T, TFilterData>>, options: ITreeOptions<T, TFilterData>): ITreeModel<T, TFilterData, TRef>;
dispose(): void {
this.disposables = dispose(this.disposables);
this.view.dispose();
......
......@@ -75,7 +75,7 @@ export class ListService implements IListService {
this.lists.push(registeredList);
// Check for currently being focused
if (widget.isDOMFocused()) {
if (widget.getHTMLElement() === document.activeElement) {
this._lastFocusedWidget = widget;
}
......
......@@ -687,7 +687,7 @@ export function getMultiSelectedEditorContexts(editorContext: IEditorCommandsCon
// First check for a focused list to return the selected items from
const list = listService.lastFocusedList;
if (list instanceof List && list.isDOMFocused()) {
if (list instanceof List && list.getHTMLElement() === document.activeElement) {
const elementToContext = (element: IEditorIdentifier | IEditorGroup) => {
if (isEditorGroup(element)) {
return { groupId: element.id, editorIndex: void 0 };
......
......@@ -30,7 +30,7 @@ function ensureDOMFocus(widget: ListWidget): void {
// DOM focus is within another focusable control within the
// list/tree item. therefor we should ensure that the
// list/tree has DOM focus again after the command ran.
if (widget && !widget.isDOMFocused()) {
if (widget && widget.getHTMLElement() !== document.activeElement) {
widget.domFocus();
}
}
......
......@@ -19,7 +19,7 @@ export function getResourceForCommand(resource: URI | object, listService: IList
}
let list = listService.lastFocusedList;
if (list && list.isDOMFocused()) {
if (list && list.getHTMLElement() === document.activeElement) {
let focus: any;
if (list instanceof List) {
const focused = list.getFocusedElements();
......@@ -42,7 +42,7 @@ export function getResourceForCommand(resource: URI | object, listService: IList
export function getMultiSelectedResources(resource: URI | object, listService: IListService, editorService: IEditorService): URI[] {
const list = listService.lastFocusedList;
if (list && list.isDOMFocused()) {
if (list && list.getHTMLElement() === document.activeElement) {
// Explorer
if (list instanceof Tree) {
const selection = list.getSelection().map((fs: ExplorerItem) => fs.resource);
......
......@@ -9,29 +9,47 @@ import { URI } from 'vs/base/common/uri';
import { TPromise } from 'vs/base/common/winjs.base';
import { Delayer } from 'vs/base/common/async';
import * as dom from 'vs/base/browser/dom';
import { IAction, IActionItem } from 'vs/base/common/actions';
import { IAction, IActionItem, Action } from 'vs/base/common/actions';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { Panel } from 'vs/workbench/browser/panel';
import { IEditorService, SIDE_GROUP, ACTIVE_GROUP } from 'vs/workbench/services/editor/common/editorService';
import Constants from 'vs/workbench/parts/markers/electron-browser/constants';
import { Marker, ResourceMarkers, RelatedInformation } from 'vs/workbench/parts/markers/electron-browser/markersModel';
import { Controller } from 'vs/workbench/parts/markers/electron-browser/markersTreeController';
import { Marker, ResourceMarkers, RelatedInformation, MarkersModel } from 'vs/workbench/parts/markers/electron-browser/markersModel';
import * as Viewer from 'vs/workbench/parts/markers/electron-browser/markersTreeViewer';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { CollapseAllAction, MarkersFilterActionItem, MarkersFilterAction, QuickFixAction, QuickFixActionItem, IMarkersFilterActionChangeEvent } from 'vs/workbench/parts/markers/electron-browser/markersPanelActions';
import { MarkersFilterActionItem, MarkersFilterAction, QuickFixAction, QuickFixActionItem, IMarkersFilterActionChangeEvent } from 'vs/workbench/parts/markers/electron-browser/markersPanelActions';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import Messages from 'vs/workbench/parts/markers/electron-browser/messages';
import { RangeHighlightDecorations } from 'vs/workbench/browser/parts/editor/rangeDecorations';
import { IThemeService } from 'vs/platform/theme/common/themeService';
import { debounceEvent } from 'vs/base/common/event';
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
import { TreeResourceNavigator, WorkbenchTree } from 'vs/platform/list/browser/listService';
import { IMarkersWorkbenchService } from 'vs/workbench/parts/markers/electron-browser/markers';
import { SimpleFileResourceDragAndDrop } from 'vs/workbench/browser/dnd';
import { IStorageService } from 'vs/platform/storage/common/storage';
import { Scope } from 'vs/workbench/common/memento';
import { localize } from 'vs/nls';
import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { ObjectTree } from 'vs/base/browser/ui/tree/objectTree';
import { Iterator } from 'vs/base/common/iterator';
import { ITreeElement } from 'vs/base/browser/ui/tree/tree';
type TreeElement = ResourceMarkers | Marker | RelatedInformation;
function createModelIterator(model: MarkersModel): Iterator<ITreeElement<TreeElement>> {
const resourcesIt = Iterator.fromArray(model.resourceMarkers);
return Iterator.map(resourcesIt, m => {
const markersIt = Iterator.fromArray(m.markers);
const children = Iterator.map(markersIt, m => {
const relatedInformationIt = Iterator.from(m.relatedInformation);
const children = Iterator.map(relatedInformationIt, r => ({ element: r }));
return { element: m, children };
});
return { element: m, children };
});
}
export class MarkersPanel extends Panel {
......@@ -40,7 +58,7 @@ export class MarkersPanel extends Panel {
private lastSelectedRelativeTop: number = 0;
private currentActiveResource: URI = null;
private tree: WorkbenchTree;
private tree: ObjectTree<TreeElement>;
private rangeHighlightDecorations: RangeHighlightDecorations;
private actions: IAction[];
......@@ -93,7 +111,9 @@ export class MarkersPanel extends Panel {
this.onDidFocus(() => this.panelFoucusContextKey.set(true));
this.onDidBlur(() => this.panelFoucusContextKey.set(false));
return this.render();
this.render();
return Promise.resolve(null);
}
public getTitle(): string {
......@@ -102,18 +122,18 @@ export class MarkersPanel extends Panel {
public layout(dimension: dom.Dimension): void {
this.treeContainer.style.height = `${dimension.height}px`;
this.tree.layout(dimension.height, dimension.width);
this.tree.layout(dimension.height);
if (this.filterInputActionItem) {
this.filterInputActionItem.toggleLayout(dimension.width < 1200);
}
}
public focus(): void {
if (this.tree.isDOMFocused()) {
if (this.tree.getHTMLElement() === document.activeElement) {
return;
}
this.tree.domFocus();
this.tree.getHTMLElement().focus();
// TODO@joao
// if (this.markersWorkbenchService.markersModel.hasFilteredResources()) {
......@@ -188,7 +208,7 @@ export class MarkersPanel extends Panel {
dom.toggleClass(this.treeContainer, 'hidden', false/* !this.markersWorkbenchService.markersModel.hasFilteredResources() */);
this.renderMessage();
// if (this.markersWorkbenchService.markersModel.hasFilteredResources()) {
return this.tree.refresh();
// return this.tree.refresh();
// }
}
return TPromise.as(null);
......@@ -209,42 +229,65 @@ export class MarkersPanel extends Panel {
this.ariaLabelElement.setAttribute('aria-live', 'polite');
}
// TODO@joao
private createTree(parent: HTMLElement): void {
this.treeContainer = dom.append(parent, dom.$('.tree-container.show-file-icons'));
const renderer = this.instantiationService.createInstance(Viewer.Renderer, (action) => this.getActionItem(action));
const dnd = this.instantiationService.createInstance(SimpleFileResourceDragAndDrop, obj => obj instanceof ResourceMarkers ? obj.resource : void 0);
const controller = this.instantiationService.createInstance(Controller, () => this.focusFilter());
this.tree = this.instantiationService.createInstance(WorkbenchTree, this.treeContainer, {
dataSource: new Viewer.DataSource(),
renderer,
controller,
accessibilityProvider: this.instantiationService.createInstance(Viewer.MarkersTreeAccessibilityProvider),
dnd
}, {
twistiePixels: 20,
ariaLabel: Messages.MARKERS_PANEL_ARIA_LABEL_PROBLEMS_TREE
});
const markerFocusContextKey = Constants.MarkerFocusContextKey.bindTo(this.tree.contextKeyService);
const relatedInformationFocusContextKey = Constants.RelatedInformationFocusContextKey.bindTo(this.tree.contextKeyService);
this._register(this.tree.onDidChangeFocus((e: { focus: any }) => {
markerFocusContextKey.set(e.focus instanceof Marker);
relatedInformationFocusContextKey.set(e.focus instanceof RelatedInformation);
}));
const focusTracker = this._register(dom.trackFocus(this.tree.getHTMLElement()));
this._register(focusTracker.onDidBlur(() => {
markerFocusContextKey.set(false);
relatedInformationFocusContextKey.set(false);
}));
const markersNavigator = this._register(new TreeResourceNavigator(this.tree, { openOnFocus: true }));
this._register(debounceEvent(markersNavigator.openResource, (last, event) => event, 75, true)(options => {
this.openFileAtElement(options.element, options.editorOptions.preserveFocus, options.sideBySide, options.editorOptions.pinned);
}));
// const dnd = this.instantiationService.createInstance(SimpleFileResourceDragAndDrop, obj => obj instanceof ResourceMarkers ? obj.resource : void 0);
// const controller = this.instantiationService.createInstance(Controller, () => this.focusFilter());
const virtualDelegate = new Viewer.VirtualDelegate();
const renderers = [
this.instantiationService.createInstance(Viewer.FileResourceMarkersRenderer),
this.instantiationService.createInstance(Viewer.ResourceMarkersRenderer),
this.instantiationService.createInstance(Viewer.MarkerRenderer, a => this.getActionItem(a)),
this.instantiationService.createInstance(Viewer.RelatedInformationRenderer)
];
this.tree = new ObjectTree<TreeElement>(
this.treeContainer,
virtualDelegate,
renderers
);
// this.tree = this.instantiationService.createInstance(WorkbenchTree, this.treeContainer, {
// dataSource: new Viewer.DataSource(),
// renderer,
// controller,
// accessibilityProvider: this.instantiationService.createInstance(Viewer.MarkersTreeAccessibilityProvider),
// dnd
// }, {
// twistiePixels: 20,
// ariaLabel: Messages.MARKERS_PANEL_ARIA_LABEL_PROBLEMS_TREE
// });
// const markerFocusContextKey = Constants.MarkerFocusContextKey.bindTo(this.tree.contextKeyService);
// const relatedInformationFocusContextKey = Constants.RelatedInformationFocusContextKey.bindTo(this.tree.contextKeyService);
// this._register(this.tree.onDidChangeFocus(elements => {
// markerFocusContextKey.set(elements.some(e => e instanceof Marker));
// relatedInformationFocusContextKey.set(elements.some(e => e instanceof RelatedInformation));
// }));
// const focusTracker = this._register(dom.trackFocus(this.tree.getHTMLElement()));
// this._register(focusTracker.onDidBlur(() => {
// markerFocusContextKey.set(false);
// relatedInformationFocusContextKey.set(false);
// }));
// const markersNavigator = this._register(new TreeResourceNavigator(this.tree, { openOnFocus: true }));
// this._register(debounceEvent(markersNavigator.openResource, (last, event) => event, 75, true)(options => {
// this.openFileAtElement(options.element, options.editorOptions.preserveFocus, options.sideBySide, options.editorOptions.pinned);
// }));
}
// TODO@joao
private createActions(): void {
this.collapseAllAction = this.instantiationService.createInstance(CollapseAllAction, this.tree, true);
this.collapseAllAction = new Action('vs.tree.collapse', localize('collapse', "Collapse"), 'monaco-tree-action collapse-all', true, async () => {
// this.tree.collapseAll();
this.tree.setSelection([]);
this.tree.setFocus([]);
this.tree.getHTMLElement().focus();
this.tree.focusFirst();
});
this.filterAction = this.instantiationService.createInstance(MarkersFilterAction, { filterText: this.panelSettings['filter'] || '', filterHistory: this.panelSettings['filterHistory'] || [], useFilesExclude: !!this.panelSettings['useFilesExclude'] });
this.actions = [this.filterAction, this.collapseAllAction];
}
......@@ -302,9 +345,9 @@ export class MarkersPanel extends Panel {
}
// TODO@joao
private async render(): Promise<void> {
private render(): void {
dom.toggleClass(this.treeContainer, 'hidden', false/* !this.markersWorkbenchService.markersModel.hasFilteredResources() */);
await this.tree.setInput(this.markersWorkbenchService.markersModel);
this.tree.setChildren(null, createModelIterator(this.markersWorkbenchService.markersModel));
this.renderMessage();
}
......@@ -387,17 +430,16 @@ export class MarkersPanel extends Panel {
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]);
this.tree.setFocus(this.tree.getSelection());
}
} else {
this.tree.expand(currentActiveResource)
.then(() => this.tree.reveal(currentActiveResource, 0))
.then(() => {
if (focus) {
this.tree.setFocus(currentActiveResource);
this.tree.setSelection([currentActiveResource]);
}
});
this.tree.expand(currentActiveResource);
this.tree.reveal(currentActiveResource, 0);
if (focus) {
this.tree.setFocus([currentActiveResource]);
this.tree.setSelection([currentActiveResource]);
}
}
} else if (focus) {
this.tree.setSelection([]);
......@@ -423,21 +465,29 @@ export class MarkersPanel extends Panel {
private updateRangeHighlights() {
this.rangeHighlightDecorations.removeHighlightRange();
if (this.tree.isDOMFocused()) {
if (this.tree.getHTMLElement() === document.activeElement) {
this.highlightCurrentSelectedMarkerRange();
}
}
private highlightCurrentSelectedMarkerRange() {
let selections = this.tree.getSelection();
if (selections && selections.length === 1 && selections[0] instanceof Marker) {
const marker: Marker = selections[0];
this.rangeHighlightDecorations.highlightRange(marker);
const selections = this.tree.getSelection();
if (selections.length !== 1) {
return;
}
const selection = selections[0];
if (!(selection instanceof Marker)) {
return;
}
this.rangeHighlightDecorations.highlightRange(selection);
}
public getFocusElement(): ResourceMarkers | Marker {
return this.tree.getFocus();
public getFocusElement(): ResourceMarkers | Marker | RelatedInformation {
return this.tree.getFocus()[0];
}
public getActionItem(action: IAction): IActionItem {
......
......@@ -17,8 +17,6 @@ import Constants from 'vs/workbench/parts/markers/electron-browser/constants';
import { IPartService } from 'vs/workbench/services/part/common/partService';
import { IPanelService } from 'vs/workbench/services/panel/common/panelService';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { CollapseAllAction as TreeCollapseAction } from 'vs/base/parts/tree/browser/treeDefaults';
import * as Tree from 'vs/base/parts/tree/browser/tree';
import { IThemeService } from 'vs/platform/theme/common/themeService';
import { attachInputBoxStyler, attachStylerCallback, attachCheckboxStyler } from 'vs/platform/theme/common/styler';
import { IMarkersWorkbenchService } from 'vs/workbench/parts/markers/electron-browser/markers';
......@@ -74,13 +72,6 @@ export class ShowProblemsPanelAction extends Action {
}
}
export class CollapseAllAction extends TreeCollapseAction {
constructor(viewer: Tree.ITree, enabled: boolean) {
super(viewer, enabled);
}
}
export interface IMarkersFilterActionChangeEvent extends IActionChangeEvent {
filterText?: boolean;
useFilesExclude?: boolean;
......
......@@ -7,7 +7,7 @@ import { TPromise, Promise } from 'vs/base/common/winjs.base';
import * as dom from 'vs/base/browser/dom';
import * as network from 'vs/base/common/network';
import * as paths from 'vs/base/common/paths';
import { IDataSource, ITree, IRenderer, IAccessibilityProvider } from 'vs/base/parts/tree/browser/tree';
import { IDataSource, ITree, IAccessibilityProvider } from 'vs/base/parts/tree/browser/tree';
import { CountBadge } from 'vs/base/browser/ui/countBadge/countBadge';
import { FileLabel, ResourceLabel } from 'vs/workbench/browser/labels';
import { HighlightedLabel } from 'vs/base/browser/ui/highlightedlabel/highlightedLabel';
......@@ -22,6 +22,8 @@ import { ActionBar, IActionItemProvider } from 'vs/base/browser/ui/actionbar/act
import { QuickFixAction } from 'vs/workbench/parts/markers/electron-browser/markersPanelActions';
import { ILabelService } from 'vs/platform/label/common/label';
import { dirname } from 'vs/base/common/resources';
import { IVirtualDelegate } from 'vs/base/browser/ui/list/list';
import { ITreeRenderer } from 'vs/base/browser/ui/tree/abstractTree';
interface IResourceMarkersTemplateData {
resourceLabel: ResourceLabel;
......@@ -93,61 +95,72 @@ export class DataSource implements IDataSource {
}
}
export class Renderer implements IRenderer {
private static readonly RESOURCE_MARKERS_TEMPLATE_ID = 'resource-markers-template';
private static readonly FILE_RESOURCE_MARKERS_TEMPLATE_ID = 'file-resource-markers-template';
private static readonly MARKER_TEMPLATE_ID = 'marker-template';
private static readonly RELATED_INFO_TEMPLATE_ID = 'related-info-template';
export class MarkersTreeAccessibilityProvider implements IAccessibilityProvider {
constructor(
private actionItemProvider: IActionItemProvider,
@IInstantiationService private instantiationService: IInstantiationService,
@IThemeService private themeService: IThemeService,
@ILabelService private labelService: ILabelService
@ILabelService private labelServie: ILabelService
) {
}
public getHeight(tree: ITree, element: any): number {
return 22;
}
public getTemplateId(tree: ITree, element: any): string {
// TODO@joao
public getAriaLabel(tree: ITree, element: any): string {
if (element instanceof ResourceMarkers) {
if ((element).resource.scheme === network.Schemas.file || (<ResourceMarkers>element).resource.scheme === network.Schemas.untitled) {
return Renderer.FILE_RESOURCE_MARKERS_TEMPLATE_ID;
} else {
return Renderer.RESOURCE_MARKERS_TEMPLATE_ID;
}
const path = this.labelServie.getUriLabel(element.resource, { relative: true }) || element.resource.fsPath;
return Messages.MARKERS_TREE_ARIA_LABEL_RESOURCE(element.markers.length/* element.filteredCount */, element.name, paths.dirname(path));
}
if (element instanceof Marker) {
return Renderer.MARKER_TEMPLATE_ID;
return Messages.MARKERS_TREE_ARIA_LABEL_MARKER(element);
}
if (element instanceof RelatedInformation) {
return Renderer.RELATED_INFO_TEMPLATE_ID;
return Messages.MARKERS_TREE_ARIA_LABEL_RELATED_INFORMATION(element.raw);
}
return '';
return null;
}
}
public renderTemplate(tree: ITree, templateId: string, container: HTMLElement): any {
dom.addClass(container, 'markers-panel-tree-entry');
switch (templateId) {
case Renderer.FILE_RESOURCE_MARKERS_TEMPLATE_ID:
return this.renderFileResourceMarkersTemplate(container);
case Renderer.RESOURCE_MARKERS_TEMPLATE_ID:
return this.renderResourceMarkersTemplate(container);
case Renderer.MARKER_TEMPLATE_ID:
return this.renderMarkerTemplate(container);
case Renderer.RELATED_INFO_TEMPLATE_ID:
return this.renderRelatedInfoTemplate(container);
const enum TemplateId {
FileResourceMarkers = 'frm',
ResourceMarkers = 'rm',
Marker = 'm',
RelatedInformation = 'ri'
}
export class VirtualDelegate implements IVirtualDelegate<ResourceMarkers | Marker | RelatedInformation> {
getHeight(): number {
return 22;
}
getTemplateId(element: ResourceMarkers | Marker | RelatedInformation): string {
if (element instanceof ResourceMarkers) {
if ((element).resource.scheme === network.Schemas.file || (<ResourceMarkers>element).resource.scheme === network.Schemas.untitled) {
return TemplateId.FileResourceMarkers;
} else {
return TemplateId.ResourceMarkers;
}
} else if (element instanceof Marker) {
return TemplateId.Marker;
} else {
return TemplateId.RelatedInformation;
}
}
}
export class ResourceMarkersRenderer implements ITreeRenderer<ResourceMarkers, IResourceMarkersTemplateData> {
private renderFileResourceMarkersTemplate(container: HTMLElement): IResourceMarkersTemplateData {
constructor(
@IInstantiationService protected instantiationService: IInstantiationService,
@IThemeService private themeService: IThemeService,
@ILabelService private labelService: ILabelService
) { }
templateId = TemplateId.ResourceMarkers;
renderTemplate(container: HTMLElement): IResourceMarkersTemplateData {
const data = <IResourceMarkersTemplateData>Object.create(null);
const resourceLabelContainer = dom.append(container, dom.$('.resource-label-container'));
data.resourceLabel = this.instantiationService.createInstance(FileLabel, resourceLabelContainer, { supportHighlights: true });
data.resourceLabel = this.createResourceLabel(resourceLabelContainer);
const badgeWrapper = dom.append(container, dom.$('.count-badge-wrapper'));
data.count = new CountBadge(badgeWrapper);
......@@ -156,37 +169,48 @@ export class Renderer implements IRenderer {
return data;
}
private renderResourceMarkersTemplate(container: HTMLElement): IResourceMarkersTemplateData {
const data = <IResourceMarkersTemplateData>Object.create(null);
// TODO@joao
renderElement(element: ResourceMarkers, _: number, templateData: IResourceMarkersTemplateData): void {
if (templateData.resourceLabel instanceof FileLabel) {
templateData.resourceLabel.setFile(element.resource/* , { matches: element.uriMatches } */);
} else {
templateData.resourceLabel.setLabel({ name: element.name, description: this.labelService.getUriLabel(dirname(element.resource), { relative: true }), resource: element.resource }/* , { matches: element.uriMatches } */);
}
const resourceLabelContainer = dom.append(container, dom.$('.resource-label-container'));
data.resourceLabel = this.instantiationService.createInstance(ResourceLabel, resourceLabelContainer, { supportHighlights: true });
templateData.count.setCount(element.markers.length/* filteredCount */);
}
const badgeWrapper = dom.append(container, dom.$('.count-badge-wrapper'));
data.count = new CountBadge(badgeWrapper);
data.styler = attachBadgeStyler(data.count, this.themeService);
disposeElement(): void {
// noop
}
return data;
disposeTemplate(templateData: IResourceMarkersTemplateData): void {
templateData.resourceLabel.dispose();
templateData.styler.dispose();
}
private renderRelatedInfoTemplate(container: HTMLElement): IRelatedInformationTemplateData {
const data: IRelatedInformationTemplateData = Object.create(null);
protected createResourceLabel(container: HTMLElement): ResourceLabel {
return this.instantiationService.createInstance(ResourceLabel, container, { supportHighlights: true });
}
}
dom.append(container, dom.$('.actions'));
dom.append(container, dom.$('.icon'));
export class FileResourceMarkersRenderer extends ResourceMarkersRenderer {
data.resourceLabel = new HighlightedLabel(dom.append(container, dom.$('.related-info-resource')));
data.lnCol = dom.append(container, dom.$('span.marker-line'));
protected createResourceLabel(container: HTMLElement): ResourceLabel {
return this.instantiationService.createInstance(FileLabel, container, { supportHighlights: true });
}
}
const separator = dom.append(container, dom.$('span.related-info-resource-separator'));
separator.textContent = ':';
separator.style.paddingRight = '4px';
export class MarkerRenderer implements ITreeRenderer<Marker, IMarkerTemplateData> {
data.description = new HighlightedLabel(dom.append(container, dom.$('.marker-description')));
return data;
}
constructor(
private actionItemProvider: IActionItemProvider,
@IInstantiationService protected instantiationService: IInstantiationService
) { }
private renderMarkerTemplate(container: HTMLElement): IMarkerTemplateData {
templateId = TemplateId.Marker;
renderTemplate(container: HTMLElement): IMarkerTemplateData {
const data: IMarkerTemplateData = Object.create(null);
const actionsContainer = dom.append(container, dom.$('.actions'));
data.actionBar = new ActionBar(actionsContainer, { actionItemProvider: this.actionItemProvider });
......@@ -198,33 +222,11 @@ export class Renderer implements IRenderer {
return data;
}
public renderElement(tree: ITree, element: any, templateId: string, templateData: any): void {
switch (templateId) {
case Renderer.FILE_RESOURCE_MARKERS_TEMPLATE_ID:
case Renderer.RESOURCE_MARKERS_TEMPLATE_ID:
return this.renderResourceMarkersElement(tree, <ResourceMarkers>element, templateData);
case Renderer.MARKER_TEMPLATE_ID:
return this.renderMarkerElement(tree, (<Marker>element), templateData);
case Renderer.RELATED_INFO_TEMPLATE_ID:
return this.renderRelatedInfoElement(tree, <RelatedInformation>element, templateData);
}
}
// TODO@joao
private renderResourceMarkersElement(tree: ITree, element: ResourceMarkers, templateData: IResourceMarkersTemplateData) {
if (templateData.resourceLabel instanceof FileLabel) {
templateData.resourceLabel.setFile(element.resource/* , { matches: element.uriMatches } */);
} else {
templateData.resourceLabel.setLabel({ name: element.name, description: this.labelService.getUriLabel(dirname(element.resource), { relative: true }), resource: element.resource }/* , { matches: element.uriMatches } */);
}
(<IResourceMarkersTemplateData>templateData).count.setCount(element.markers.length/* filteredCount */);
}
// TODO@joao
private renderMarkerElement(tree: ITree, element: Marker, templateData: IMarkerTemplateData) {
renderElement(element: Marker, _: number, templateData: IMarkerTemplateData): void {
let marker = element.marker;
templateData.icon.className = 'icon ' + Renderer.iconClassNameFor(marker);
templateData.icon.className = 'icon ' + MarkerRenderer.iconClassNameFor(marker);
templateData.source.set(marker.source/* , element.sourceMatches */);
dom.toggleClass(templateData.source.element, 'marker-source', !!marker.source);
......@@ -240,16 +242,16 @@ export class Renderer implements IRenderer {
templateData.code.set(marker.code || ''/* , element.codeMatches */);
templateData.lnCol.textContent = Messages.MARKERS_PANEL_AT_LINE_COL_NUMBER(marker.startLineNumber, marker.startColumn);
}
disposeElement(): void {
// noop
}
// TODO@joao
private renderRelatedInfoElement(tree: ITree, element: RelatedInformation, templateData: IRelatedInformationTemplateData) {
templateData.resourceLabel.set(paths.basename(element.raw.resource.fsPath)/* , element.uriMatches */);
templateData.resourceLabel.element.title = this.labelService.getUriLabel(element.raw.resource, { relative: true });
templateData.lnCol.textContent = Messages.MARKERS_PANEL_AT_LINE_COL_NUMBER(element.raw.startLineNumber, element.raw.startColumn);
templateData.description.set(element.raw.message/* , element.messageMatches */);
templateData.description.element.title = element.raw.message;
disposeTemplate(templateData: IMarkerTemplateData): void {
templateData.description.dispose();
templateData.source.dispose();
templateData.actionBar.dispose();
}
private static iconClassNameFor(element: IMarker): string {
......@@ -265,41 +267,48 @@ export class Renderer implements IRenderer {
}
return '';
}
public disposeTemplate(tree: ITree, templateId: string, templateData: any): void {
if (templateId === Renderer.RESOURCE_MARKERS_TEMPLATE_ID || templateId === Renderer.FILE_RESOURCE_MARKERS_TEMPLATE_ID) {
(<IResourceMarkersTemplateData>templateData).resourceLabel.dispose();
(<IResourceMarkersTemplateData>templateData).styler.dispose();
} else if (templateId === Renderer.MARKER_TEMPLATE_ID) {
(<IMarkerTemplateData>templateData).description.dispose();
(<IMarkerTemplateData>templateData).source.dispose();
(<IMarkerTemplateData>templateData).actionBar.dispose();
} else if (templateId === Renderer.RELATED_INFO_TEMPLATE_ID) {
(<IRelatedInformationTemplateData>templateData).description.dispose();
(<IRelatedInformationTemplateData>templateData).resourceLabel.dispose();
}
}
}
export class MarkersTreeAccessibilityProvider implements IAccessibilityProvider {
export class RelatedInformationRenderer implements ITreeRenderer<RelatedInformation, IRelatedInformationTemplateData> {
constructor(
@ILabelService private labelServie: ILabelService
) {
@ILabelService private labelService: ILabelService
) { }
templateId = TemplateId.Marker;
renderTemplate(container: HTMLElement): IRelatedInformationTemplateData {
const data: IRelatedInformationTemplateData = Object.create(null);
dom.append(container, dom.$('.actions'));
dom.append(container, dom.$('.icon'));
data.resourceLabel = new HighlightedLabel(dom.append(container, dom.$('.related-info-resource')));
data.lnCol = dom.append(container, dom.$('span.marker-line'));
const separator = dom.append(container, dom.$('span.related-info-resource-separator'));
separator.textContent = ':';
separator.style.paddingRight = '4px';
data.description = new HighlightedLabel(dom.append(container, dom.$('.marker-description')));
return data;
}
// TODO@joao
public getAriaLabel(tree: ITree, element: any): string {
if (element instanceof ResourceMarkers) {
const path = this.labelServie.getUriLabel(element.resource, { relative: true }) || element.resource.fsPath;
return Messages.MARKERS_TREE_ARIA_LABEL_RESOURCE(element.markers.length/* element.filteredCount */, element.name, paths.dirname(path));
}
if (element instanceof Marker) {
return Messages.MARKERS_TREE_ARIA_LABEL_MARKER(element);
}
if (element instanceof RelatedInformation) {
return Messages.MARKERS_TREE_ARIA_LABEL_RELATED_INFORMATION(element.raw);
}
return null;
renderElement(element: RelatedInformation, _: number, templateData: IRelatedInformationTemplateData): void {
templateData.resourceLabel.set(paths.basename(element.raw.resource.fsPath)/* , element.uriMatches */);
templateData.resourceLabel.element.title = this.labelService.getUriLabel(element.raw.resource, { relative: true });
templateData.lnCol.textContent = Messages.MARKERS_PANEL_AT_LINE_COL_NUMBER(element.raw.startLineNumber, element.raw.startColumn);
templateData.description.set(element.raw.message/* , element.messageMatches */);
templateData.description.element.title = element.raw.message;
}
}
disposeElement(): void {
// noop
}
disposeTemplate(templateData: IRelatedInformationTemplateData): void {
templateData.description.dispose();
templateData.resourceLabel.dispose();
}
}
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册