package name.abuchen.portfolio.ui.views.taxonomy;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.RowLayout;
import org.eclipse.swt.widgets.Canvas;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Listener;
import de.engehausen.treemap.IRectangle;
import de.engehausen.treemap.ITreeModel;
import de.engehausen.treemap.swt.TreeMap;
import name.abuchen.portfolio.money.Values;
import name.abuchen.portfolio.ui.util.Colors;
/* package */class TreeMapLegend extends Composite
{
private TaxonomyModel model;
private TaxonomyNodeRenderer renderer;
private TaxonomyNode rootItem;
public TreeMapLegend(Composite parent, TreeMap<TaxonomyNode> treeMap, TaxonomyModel model,
TaxonomyNodeRenderer renderer)
{
super(parent, SWT.NONE);
this.model = model;
this.renderer = renderer;
setBackground(parent.getBackground());
RowLayout layout = new RowLayout(SWT.HORIZONTAL);
layout.wrap = true;
layout.pack = true;
layout.justify = false;
setLayout(layout);
treeMap.addSelectionChangeListener(
(treeModel, rectangle, label) -> TreeMapLegend.this.selectionChanged(treeModel));
}
public void setRootItem(TaxonomyNode rootItem)
{
this.rootItem = rootItem;
for (Control control : this.getChildren())
control.dispose();
TaxonomyNode root = model.getChartRenderingRootNode();
boolean hasParent = false;
List<TaxonomyNode> path = rootItem.getPath();
for (int ii = 0; ii < path.size(); ii++)
{
TaxonomyNode item = path.get(ii);
if (!hasParent && !item.equals(root))
continue;
hasParent = true;
new LegendItem(this, item);
}
if (hasParent && !rootItem.getChildren().isEmpty())
{
Label l = new Label(this, SWT.NONE);
l.setText(">>"); //$NON-NLS-1$
l.setBackground(this.getBackground());
}
List<TaxonomyNode> children = new ArrayList<>(rootItem.getChildren());
Collections.sort(children, (o1, o2) -> Long.compare(o2.getActual().getAmount(), o1.getActual().getAmount()));
for (TaxonomyNode child : children)
new LegendItem(this, child);
pack();
getParent().layout();
}
private void selectionChanged(ITreeModel<IRectangle<TaxonomyNode>> model)
{
// find out if root changed (drill-down)
TaxonomyNode newRoot = model.getRoot().getNode();
if (!newRoot.equals(rootItem))
setRootItem(newRoot);
}
public class LegendItem extends Canvas implements Listener
{
private final TaxonomyNode item;
public LegendItem(Composite parent, TaxonomyNode item)
{
super(parent, SWT.NO_BACKGROUND);
this.item = item;
addListener(SWT.Paint, this);
addListener(SWT.Resize, this);
}
@Override
public void handleEvent(Event event)
{
switch (event.type)
{
case SWT.Paint:
paintControl(event);
break;
case SWT.Resize:
redraw();
break;
default:
break;
}
}
private void paintControl(Event e)
{
Color oldForeground = e.gc.getForeground();
Color oldBackground = e.gc.getBackground();
Point size = getSize();
Rectangle r = new Rectangle(0, 0, size.x, size.y);
renderer.drawRectangle(rootItem, item, e.gc, r);
String text = item.getName();
String info = getInfo();
GC gc = e.gc;
gc.setForeground(Colors.getTextColor(gc.getBackground()));
gc.drawString(text, 2, 2, true);
Point extent = gc.stringExtent(text);
gc.drawString(info, 2, extent.y + 1, true);
e.gc.setForeground(oldForeground);
e.gc.setBackground(oldBackground);
}
@Override
public Point computeSize(int wHint, int hHint, boolean changed)
{
String text = item.getName();
String info = getInfo();
GC gc = new GC(this);
Point extentText = gc.stringExtent(text);
Point extentInfo = gc.stringExtent(info);
gc.dispose();
return new Point(Math.max(extentText.x, extentInfo.x) + 4, extentText.y + extentInfo.y + 4);
}
private String getInfo()
{
return String.format("%s (%s%%)", Values.Money.format(item.getActual()), //$NON-NLS-1$
Values.Percent.format((double) item.getActual().getAmount()
/ (double) model.getVirtualRootNode().getActual().getAmount()));
}
}
}