package name.abuchen.portfolio.ui.views.dataseries;
import java.util.ResourceBundle;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.action.Separator;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.jface.resource.LocalResourceManager;
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.RGB;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.RowLayout;
import org.eclipse.swt.widgets.Canvas;
import org.eclipse.swt.widgets.ColorDialog;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.swtchart.LineStyle;
import name.abuchen.portfolio.ui.Messages;
import name.abuchen.portfolio.ui.util.SimpleAction;
/**
* A legend for charts to configure data series, e.g. color, area fill, and line
* type.
*/
public class DataSeriesChartLegend extends Composite
{
private final DataSeriesConfigurator configurator;
private final LocalResourceManager resources;
/**
* Constructor.
*
* @param parent
* the parent composite
* @param configurator
* the chart configurator
*/
public DataSeriesChartLegend(Composite parent, DataSeriesConfigurator configurator)
{
super(parent, SWT.NONE);
this.configurator = configurator;
this.resources = new LocalResourceManager(JFaceResources.getResources(), parent);
setBackground(Display.getDefault().getSystemColor(SWT.COLOR_WHITE));
RowLayout layout = new RowLayout();
layout.wrap = true;
layout.pack = true;
layout.fill = true;
setLayout(layout);
for (DataSeries series : configurator.getSelectedDataSeries())
new PaintItem(this, series);
this.configurator.addListener(() -> onUpdate());
}
private void onUpdate()
{
for (Control child : getChildren())
child.dispose();
for (DataSeries series : configurator.getSelectedDataSeries())
new PaintItem(this, series);
layout();
getParent().layout();
}
private static final class PaintItem extends Canvas implements Listener // NOSONAR
{
private static final ResourceBundle LABELS = ResourceBundle.getBundle("name.abuchen.portfolio.ui.views.labels"); //$NON-NLS-1$
final DataSeries series;
private PaintItem(Composite parent, DataSeries series)
{
super(parent, SWT.NONE);
this.series = series;
setBackground(parent.getDisplay().getSystemColor(SWT.COLOR_WHITE));
addListener(SWT.Paint, this);
addListener(SWT.Resize, this);
MenuManager menuManager = new MenuManager();
menuManager.setRemoveAllWhenShown(true);
menuManager.addMenuListener(this::seriesMenuAboutToShow);
setMenu(menuManager.createContextMenu(this));
}
@Override
public void handleEvent(Event event)
{
switch (event.type)
{
case SWT.Paint:
paintControl(event);
break;
case SWT.Resize:
redraw();
break;
default:
break;
}
}
private Color colorFor(RGB color)
{
DataSeriesChartLegend legend = (DataSeriesChartLegend) getParent();
return legend.resources.createColor(color);
}
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.y, size.y);
GC gc = e.gc;
gc.setBackground(colorFor(series.getColor()));
gc.fillRectangle(r.x, r.y, r.width, r.height);
gc.setForeground(Display.getCurrent().getSystemColor(SWT.COLOR_BLACK));
gc.drawRectangle(r.x, r.y, r.width - 1, r.height - 1);
String text = series.getLabel();
e.gc.setForeground(Display.getCurrent().getSystemColor(SWT.COLOR_BLACK));
e.gc.drawString(text, size.y + 2, 1, true);
e.gc.setForeground(oldForeground);
e.gc.setBackground(oldBackground);
}
@Override
public Point computeSize(int wHint, int hHint, boolean changed)
{
String text = series.getLabel();
GC gc = new GC(this);
Point extentText = gc.stringExtent(text);
gc.dispose();
return new Point(extentText.x + extentText.y + 12, extentText.y + 2);
}
private void seriesMenuAboutToShow(IMenuManager manager) // NOSONAR
{
manager.add(new Action(Messages.ChartSeriesPickerColor)
{
@Override
public void run()
{
ColorDialog colorDialog = new ColorDialog(Display.getDefault().getActiveShell());
colorDialog.setRGB(series.getColor());
RGB newColor = colorDialog.open();
if (newColor != null)
{
series.setColor(newColor);
((DataSeriesChartLegend) getParent()).configurator.fireUpdate();
}
}
});
if (series.isLineChart())
{
MenuManager lineStyle = new MenuManager(Messages.ChartSeriesPickerLineStyle);
for (final LineStyle style : LineStyle.values())
{
if (style == LineStyle.NONE)
continue;
Action action = new SimpleAction(LABELS.getString("lineStyle." + style.name()), a -> { //$NON-NLS-1$
series.setLineStyle(style);
((DataSeriesChartLegend) getParent()).configurator.fireUpdate();
});
action.setChecked(style == series.getLineStyle());
lineStyle.add(action);
}
manager.add(lineStyle);
Action actionShowArea = new SimpleAction(Messages.ChartSeriesPickerShowArea, a -> {
series.setShowArea(!series.isShowArea());
((DataSeriesChartLegend) getParent()).configurator.fireUpdate();
});
actionShowArea.setChecked(series.isShowArea());
manager.add(actionShowArea);
}
manager.add(new Separator());
manager.add(new SimpleAction(Messages.ChartSeriesPickerRemove,
a -> ((DataSeriesChartLegend) getParent()).configurator.doDeleteSeries(series)));
}
}
}