提交 e6d219aa 编写于 作者: J Joao Moreno

markers tree: filter count

上级 5f69bcbc
......@@ -169,6 +169,7 @@ export abstract class AbstractTree<T, TFilterData, TRef> implements IDisposable
protected disposables: IDisposable[] = [];
readonly onDidChangeCollapseState: Event<ITreeNode<T, TFilterData>>;
readonly onDidChangeRenderNodeCount: Event<ITreeNode<T, TFilterData>>;
@memoize get onDidChangeFocus(): Event<T[]> {
return mapEvent(this.view.onFocusChange, e => e.elements.map(e => e.element));
......@@ -198,6 +199,7 @@ export abstract class AbstractTree<T, TFilterData, TRef> implements IDisposable
this.model = this.createModel(this.view, options);
onDidChangeCollapseStateRelay.input = this.model.onDidChangeCollapseState;
this.onDidChangeCollapseState = this.model.onDidChangeCollapseState;
this.onDidChangeRenderNodeCount = this.model.onDidChangeRenderNodeCount;
this.view.onMouseClick(this.onMouseClick, this, this.disposables);
......
......@@ -6,7 +6,7 @@
import { ITreeOptions, ComposedTreeDelegate, createComposedTreeListOptions } from 'vs/base/browser/ui/tree/abstractTree';
import { ObjectTree } from 'vs/base/browser/ui/tree/objectTree';
import { IVirtualDelegate } from 'vs/base/browser/ui/list/list';
import { ITreeElement, ITreeNode, ITreeRenderer, ITreeRenderElement } from 'vs/base/browser/ui/tree/tree';
import { ITreeElement, ITreeNode, ITreeRenderer } from 'vs/base/browser/ui/tree/tree';
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
import { Emitter, Event } from 'vs/base/common/event';
import { timeout } from 'vs/base/common/async';
......@@ -39,11 +39,15 @@ interface IDataTreeListTemplateData<T> {
templateData: T;
}
function unpack<T, TFilterData>(node: ITreeRenderElement<IDataTreeNode<T>, TFilterData>): ITreeRenderElement<T, TFilterData> {
return {
get element() { return node.element.element; },
get filterData() { return node.filterData; }
};
function unpack<T, TFilterData>(node: ITreeNode<IDataTreeNode<T>, TFilterData>): ITreeNode<T, TFilterData> {
return new Proxy(Object.create(null), {
get: (_: any, name: string) => {
switch (name) {
case 'element': return node.element.element;
default: return node[name];
}
}
});
}
class DataTreeRenderer<T, TFilterData, TTemplateData> implements ITreeRenderer<IDataTreeNode<T>, TFilterData, IDataTreeListTemplateData<TTemplateData>> {
......@@ -64,7 +68,7 @@ class DataTreeRenderer<T, TFilterData, TTemplateData> implements ITreeRenderer<I
return { templateData };
}
renderElement(element: ITreeRenderElement<IDataTreeNode<T>, TFilterData>, index: number, templateData: IDataTreeListTemplateData<TTemplateData>): void {
renderElement(element: ITreeNode<IDataTreeNode<T>, TFilterData>, index: number, templateData: IDataTreeListTemplateData<TTemplateData>): void {
this.renderer.renderElement(unpack(element), index, templateData.templateData);
}
......@@ -77,7 +81,7 @@ class DataTreeRenderer<T, TFilterData, TTemplateData> implements ITreeRenderer<I
return false;
}
disposeElement(element: ITreeRenderElement<IDataTreeNode<T>, TFilterData>, index: number, templateData: IDataTreeListTemplateData<TTemplateData>): void {
disposeElement(element: ITreeNode<IDataTreeNode<T>, TFilterData>, index: number, templateData: IDataTreeListTemplateData<TTemplateData>): void {
this.renderer.disposeElement(unpack(element), index, templateData.templateData);
}
......
......@@ -5,7 +5,7 @@
import { ISpliceable } from 'vs/base/common/sequence';
import { Iterator, ISequence } from 'vs/base/common/iterator';
import { Emitter, Event } from 'vs/base/common/event';
import { Emitter, Event, EventBufferer } from 'vs/base/common/event';
import { tail2 } from 'vs/base/common/arrays';
import { ITreeFilterDataResult, TreeVisibility, ITreeFilter, ITreeOptions, ITreeModel, ITreeNode, ITreeElement } from 'vs/base/browser/ui/tree/tree';
......@@ -56,8 +56,13 @@ export class IndexTreeModel<T, TFilterData = void> implements ITreeModel<T, TFil
filterData: undefined
};
private eventBufferer = new EventBufferer();
private _onDidChangeCollapseState = new Emitter<ITreeNode<T, TFilterData>>();
readonly onDidChangeCollapseState: Event<ITreeNode<T, TFilterData>> = this._onDidChangeCollapseState.event;
readonly onDidChangeCollapseState: Event<ITreeNode<T, TFilterData>> = this.eventBufferer.wrapEvent(this._onDidChangeCollapseState.event);
private _onDidChangeRenderNodeCount = new Emitter<ITreeNode<T, TFilterData>>();
readonly onDidChangeRenderNodeCount: Event<ITreeNode<T, TFilterData>> = this.eventBufferer.wrapEvent(this._onDidChangeRenderNodeCount.event);
private filter?: ITreeFilter<T, TFilterData>;
......@@ -116,12 +121,12 @@ export class IndexTreeModel<T, TFilterData = void> implements ITreeModel<T, TFil
setCollapsed(location: number[], collapsed: boolean): boolean {
const { node, listIndex, revealed } = this.getNodeWithListIndex(location);
return this._setCollapsed(node, listIndex, revealed, collapsed);
return this.eventBufferer.bufferEvents(() => this._setCollapsed(node, listIndex, revealed, collapsed));
}
toggleCollapsed(location: number[]): void {
const { node, listIndex, revealed } = this.getNodeWithListIndex(location);
this._setCollapsed(node, listIndex, revealed);
this.eventBufferer.bufferEvents(() => this._setCollapsed(node, listIndex, revealed));
}
// // TODO@joao cleanup
......@@ -259,6 +264,7 @@ export class IndexTreeModel<T, TFilterData = void> implements ITreeModel<T, TFil
}
}
this._onDidChangeRenderNodeCount.fire(node);
return node.renderNodeCount;
}
......@@ -312,6 +318,7 @@ export class IndexTreeModel<T, TFilterData = void> implements ITreeModel<T, TFil
node.renderNodeCount += result.length - resultStartLength;
}
this._onDidChangeRenderNodeCount.fire(node);
return node.visible;
}
......@@ -322,6 +329,7 @@ export class IndexTreeModel<T, TFilterData = void> implements ITreeModel<T, TFil
while (node) {
node.renderNodeCount += diff;
this._onDidChangeRenderNodeCount.fire(node);
node = node.parent;
}
}
......
......@@ -19,12 +19,14 @@ export class ObjectTreeModel<T extends NonNullable<any>, TFilterData = void> imp
private nodes = new Map<T, ITreeNode<T, TFilterData>>();
readonly onDidChangeCollapseState: Event<ITreeNode<T, TFilterData>>;
readonly onDidChangeRenderNodeCount: Event<ITreeNode<T, TFilterData>>;
get size(): number { return this.nodes.size; }
constructor(list: ISpliceable<ITreeNode<T, TFilterData>>, options: IObjectTreeModelOptions<T, TFilterData> = {}) {
this.model = new IndexTreeModel(list, options);
this.onDidChangeCollapseState = this.model.onDidChangeCollapseState;
this.onDidChangeRenderNodeCount = this.model.onDidChangeRenderNodeCount;
}
setChildren(element: T | null, children?: ISequence<ITreeElement<T>>): Iterator<ITreeElement<T>> {
......
......@@ -49,6 +49,7 @@ export interface ITreeNode<T, TFilterData = void> {
export interface ITreeModel<T, TFilterData, TRef> {
readonly onDidChangeCollapseState: Event<ITreeNode<T, TFilterData>>;
readonly onDidChangeRenderNodeCount: Event<ITreeNode<T, TFilterData>>;
getListIndex(ref: TRef): number;
setCollapsed(ref: TRef, collapsed: boolean): boolean;
......@@ -64,12 +65,7 @@ export interface ITreeModel<T, TFilterData, TRef> {
getLastElementAncestor(location: TRef): T | null;
}
export interface ITreeRenderElement<T, TFilterData> {
readonly element: T;
readonly filterData: TFilterData | undefined;
}
export interface ITreeRenderer<T, TFilterData, TTemplateData> extends IRenderer<ITreeRenderElement<T, TFilterData>, TTemplateData> {
export interface ITreeRenderer<T, TFilterData, TTemplateData> extends IRenderer<ITreeNode<T, TFilterData>, TTemplateData> {
renderTwistie?(element: T, twistieElement: HTMLElement): boolean;
onDidChangeTwistieState?: Event<T>;
}
\ No newline at end of file
......@@ -398,12 +398,13 @@ export class EventBufferer {
};
}
bufferEvents(fn: () => void): void {
bufferEvents<R = void>(fn: () => R): R {
const buffer: Function[] = [];
this.buffers.push(buffer);
fn();
const r = fn();
this.buffers.pop();
buffer.forEach(flush => flush());
return r;
}
}
......
......@@ -28,8 +28,8 @@ import { Scope } from 'vs/workbench/common/memento';
import { localize } from 'vs/nls';
import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { Iterator } from 'vs/base/common/iterator';
import { ITreeElement } from 'vs/base/browser/ui/tree/tree';
import { debounceEvent } from 'vs/base/common/event';
import { ITreeElement, ITreeNode } from 'vs/base/browser/ui/tree/tree';
import { debounceEvent, Relay } from 'vs/base/common/event';
import { WorkbenchObjectTree } from 'vs/platform/list/browser/listService';
import { FilterOptions } from 'vs/workbench/parts/markers/electron-browser/markersFilterOptions';
import { IExpression, getEmptyExpression } from 'vs/base/common/glob';
......@@ -280,10 +280,12 @@ export class MarkersPanel extends Panel {
// const dnd = this.instantiationService.createInstance(SimpleFileResourceDragAndDrop, obj => obj instanceof ResourceMarkers ? obj.resource : void 0);
// const controller = this.instantiationService.createInstance(Controller, () => this.focusFilter());
const onDidChangeRenderNodeCount = new Relay<ITreeNode<any, any>>();
const virtualDelegate = new Viewer.VirtualDelegate();
const renderers = [
this.instantiationService.createInstance(Viewer.FileResourceMarkersRenderer),
this.instantiationService.createInstance(Viewer.ResourceMarkersRenderer),
this.instantiationService.createInstance(Viewer.FileResourceMarkersRenderer, onDidChangeRenderNodeCount.event),
this.instantiationService.createInstance(Viewer.ResourceMarkersRenderer, onDidChangeRenderNodeCount.event),
this.instantiationService.createInstance(Viewer.MarkerRenderer, a => this.getActionItem(a)),
this.instantiationService.createInstance(Viewer.RelatedInformationRenderer)
];
......@@ -298,6 +300,8 @@ export class MarkersPanel extends Panel {
}
) as any as WorkbenchObjectTree<TreeElement>;
onDidChangeRenderNodeCount.input = this.tree.onDidChangeRenderNodeCount;
// this.tree = this.instantiationService.createInstance(WorkbenchTree, this.treeContainer, {
// dataSource: new Viewer.DataSource(),
// renderer,
......
......@@ -16,15 +16,16 @@ import Messages from 'vs/workbench/parts/markers/electron-browser/messages';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { attachBadgeStyler } from 'vs/platform/theme/common/styler';
import { IThemeService } from 'vs/platform/theme/common/themeService';
import { IDisposable } from 'vs/base/common/lifecycle';
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
import { ActionBar, IActionItemProvider } from 'vs/base/browser/ui/actionbar/actionbar';
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 { ITreeFilter, TreeVisibility, TreeFilterResult, ITreeRenderer, ITreeRenderElement } from 'vs/base/browser/ui/tree/tree';
import { ITreeFilter, TreeVisibility, TreeFilterResult, ITreeRenderer, ITreeNode } from 'vs/base/browser/ui/tree/tree';
import { FilterOptions } from 'vs/workbench/parts/markers/electron-browser/markersFilterOptions';
import { IMatch } from 'vs/base/common/filters';
import { Event } from 'vs/base/common/event';
interface IResourceMarkersTemplateData {
resourceLabel: ResourceLabel;
......@@ -126,11 +127,17 @@ type FilterData = ResourceMarkersFilterData | MarkerFilterData | RelatedInformat
export class ResourceMarkersRenderer implements ITreeRenderer<ResourceMarkers, ResourceMarkersFilterData, IResourceMarkersTemplateData> {
private renderedNodes = new Map<ITreeNode<ResourceMarkers, ResourceMarkersFilterData>, IResourceMarkersTemplateData>();
private disposables: IDisposable[] = [];
constructor(
onDidChangeRenderNodeCount: Event<ITreeNode<ResourceMarkers, ResourceMarkersFilterData>>,
@IInstantiationService protected instantiationService: IInstantiationService,
@IThemeService private themeService: IThemeService,
@ILabelService private labelService: ILabelService
) { }
) {
onDidChangeRenderNodeCount(this.onDidChangeRenderNodeCount, this, this.disposables);
}
templateId = TemplateId.ResourceMarkers;
......@@ -147,10 +154,9 @@ export class ResourceMarkersRenderer implements ITreeRenderer<ResourceMarkers, R
return data;
}
// TODO@joao
renderElement(element: ITreeRenderElement<ResourceMarkers, ResourceMarkersFilterData>, _: number, templateData: IResourceMarkersTemplateData): void {
const resourceMarkers = element.element;
const uriMatches = element.filterData && element.filterData.uriMatches || [];
renderElement(node: ITreeNode<ResourceMarkers, ResourceMarkersFilterData>, _: number, templateData: IResourceMarkersTemplateData): void {
const resourceMarkers = node.element;
const uriMatches = node.filterData && node.filterData.uriMatches || [];
if (templateData.resourceLabel instanceof FileLabel) {
templateData.resourceLabel.setFile(resourceMarkers.resource, { matches: uriMatches });
......@@ -158,11 +164,12 @@ export class ResourceMarkersRenderer implements ITreeRenderer<ResourceMarkers, R
templateData.resourceLabel.setLabel({ name: resourceMarkers.name, description: this.labelService.getUriLabel(dirname(resourceMarkers.resource), { relative: true }), resource: resourceMarkers.resource }, { matches: uriMatches });
}
// templateData.count.setCount(element.markers.length/* filteredCount */);
this.updateCount(node, templateData);
this.renderedNodes.set(node, templateData);
}
disposeElement(): void {
// noop
disposeElement(node: ITreeNode<ResourceMarkers, ResourceMarkersFilterData>): void {
this.renderedNodes.delete(node);
}
disposeTemplate(templateData: IResourceMarkersTemplateData): void {
......@@ -173,6 +180,24 @@ export class ResourceMarkersRenderer implements ITreeRenderer<ResourceMarkers, R
protected createResourceLabel(container: HTMLElement): ResourceLabel {
return this.instantiationService.createInstance(ResourceLabel, container, { supportHighlights: true });
}
private onDidChangeRenderNodeCount(node: ITreeNode<ResourceMarkers, ResourceMarkersFilterData>): void {
const templateData = this.renderedNodes.get(node);
if (!templateData) {
return;
}
this.updateCount(node, templateData);
}
private updateCount(node: ITreeNode<ResourceMarkers, ResourceMarkersFilterData>, templateData: IResourceMarkersTemplateData): void {
templateData.count.setCount(node.children.reduce((r, n) => r + (n.visible ? 1 : 0), 0));
}
dispose(): void {
this.disposables = dispose(this.disposables);
}
}
export class FileResourceMarkersRenderer extends ResourceMarkersRenderer {
......@@ -205,11 +230,11 @@ export class MarkerRenderer implements ITreeRenderer<Marker, MarkerFilterData, I
return data;
}
renderElement(element: ITreeRenderElement<Marker, MarkerFilterData>, _: number, templateData: IMarkerTemplateData): void {
const marker = element.element.marker;
const sourceMatches = element.filterData && element.filterData.sourceMatches || [];
const messageMatches = element.filterData && element.filterData.messageMatches || [];
const codeMatches = element.filterData && element.filterData.codeMatches || [];
renderElement(node: ITreeNode<Marker, MarkerFilterData>, _: number, templateData: IMarkerTemplateData): void {
const marker = node.element.marker;
const sourceMatches = node.filterData && node.filterData.sourceMatches || [];
const messageMatches = node.filterData && node.filterData.messageMatches || [];
const codeMatches = node.filterData && node.filterData.codeMatches || [];
templateData.icon.className = 'icon ' + MarkerRenderer.iconClassNameFor(marker);
......@@ -217,7 +242,7 @@ export class MarkerRenderer implements ITreeRenderer<Marker, MarkerFilterData, I
dom.toggleClass(templateData.source.element, 'marker-source', !!marker.source);
templateData.actionBar.clear();
const quickFixAction = this.instantiationService.createInstance(QuickFixAction, element.element);
const quickFixAction = this.instantiationService.createInstance(QuickFixAction, node.element);
templateData.actionBar.push([quickFixAction], { icon: true, label: false });
templateData.description.set(marker.message, messageMatches);
......@@ -279,10 +304,10 @@ export class RelatedInformationRenderer implements ITreeRenderer<RelatedInformat
return data;
}
renderElement(element: ITreeRenderElement<RelatedInformation, RelatedInformationFilterData>, _: number, templateData: IRelatedInformationTemplateData): void {
const relatedInformation = element.element.raw;
const uriMatches = element.filterData && element.filterData.uriMatches || [];
const messageMatches = element.filterData && element.filterData.messageMatches || [];
renderElement(node: ITreeNode<RelatedInformation, RelatedInformationFilterData>, _: number, templateData: IRelatedInformationTemplateData): void {
const relatedInformation = node.element.raw;
const uriMatches = node.filterData && node.filterData.uriMatches || [];
const messageMatches = node.filterData && node.filterData.messageMatches || [];
templateData.resourceLabel.set(paths.basename(relatedInformation.resource.fsPath), uriMatches);
templateData.resourceLabel.element.title = this.labelService.getUriLabel(relatedInformation.resource, { relative: true });
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册