package name.abuchen.portfolio.ui.views; import java.io.File; import java.io.IOException; import java.text.DecimalFormat; import java.text.MessageFormat; import org.eclipse.jface.action.Action; import org.eclipse.jface.action.ActionContributionItem; import org.eclipse.jface.action.IMenuManager; import org.eclipse.jface.action.Separator; import org.eclipse.jface.layout.GridDataFactory; import org.eclipse.jface.layout.GridLayoutFactory; import org.eclipse.jface.resource.JFaceResources; import org.eclipse.jface.resource.LocalResourceManager; import org.eclipse.swt.SWT; import org.eclipse.swt.events.PaintEvent; import org.eclipse.swt.graphics.Color; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.ToolBar; import org.swtchart.IAxis; import org.swtchart.ICustomPaintListener; import org.swtchart.ILineSeries; import org.swtchart.IPlotArea; import org.swtchart.ISeries; import name.abuchen.portfolio.math.Risk.Volatility; import name.abuchen.portfolio.snapshot.PerformanceIndex; import name.abuchen.portfolio.ui.Images; import name.abuchen.portfolio.ui.Messages; import name.abuchen.portfolio.ui.util.AbstractCSVExporter; import name.abuchen.portfolio.ui.util.AbstractDropDown; import name.abuchen.portfolio.ui.util.SimpleAction; import name.abuchen.portfolio.ui.util.chart.ScatterChart; import name.abuchen.portfolio.ui.util.chart.ScatterChartCSVExporter; import name.abuchen.portfolio.ui.views.dataseries.DataSeries; import name.abuchen.portfolio.ui.views.dataseries.DataSeriesCache; import name.abuchen.portfolio.ui.views.dataseries.DataSeriesChartLegend; import name.abuchen.portfolio.ui.views.dataseries.DataSeriesConfigurator; public class ReturnsVolatilityChartView extends AbstractHistoricView { private ScatterChart chart; private LocalResourceManager resources; private DataSeriesConfigurator configurator; private DataSeriesCache cache; @Override protected String getDefaultTitle() { return Messages.LabelHistoricalReturnsAndVolatiltity; } @Override protected void addButtons(ToolBar toolBar) { super.addButtons(toolBar); new ExportDropDown(toolBar); addConfigButton(toolBar); } private void addConfigButton(ToolBar toolBar) { Action save = new SimpleAction(Messages.MenuSaveChart, a -> configurator.showSaveMenu(getActiveShell())); save.setImageDescriptor(Images.SAVE.descriptor()); save.setToolTipText(Messages.MenuSaveChart); new ActionContributionItem(save).fill(toolBar, -1); Action config = new SimpleAction(Messages.MenuConfigureChart, a -> configurator.showMenu(getActiveShell())); config.setImageDescriptor(Images.CONFIG.descriptor()); config.setToolTipText(Messages.MenuConfigureChart); new ActionContributionItem(config).fill(toolBar, -1); } @Override protected Composite createBody(Composite parent) { cache = make(DataSeriesCache.class); Composite composite = new Composite(parent, SWT.NONE); composite.setBackground(Display.getDefault().getSystemColor(SWT.COLOR_WHITE)); resources = new LocalResourceManager(JFaceResources.getResources(), composite); chart = new ScatterChart(composite); chart.getTitle().setVisible(false); IAxis xAxis = chart.getAxisSet().getXAxis(0); xAxis.getTitle().setText(Messages.LabelVolatility); xAxis.getTick().setFormat(new DecimalFormat("0.##%")); //$NON-NLS-1$ IAxis yAxis = chart.getAxisSet().getYAxis(0); yAxis.getTitle().setText(Messages.LabelPeformanceTTWROR); yAxis.getTick().setFormat(new DecimalFormat("0.##%")); //$NON-NLS-1$ ((IPlotArea) chart.getPlotArea()).addCustomPaintListener(new ICustomPaintListener() { @Override public void paintControl(PaintEvent e) { int y = xAxis.getPixelCoordinate(0); e.gc.drawLine(y, 0, y, e.height); int x = yAxis.getPixelCoordinate(0); e.gc.drawLine(0, x, e.width, x); } @Override public boolean drawBehindSeries() { return true; } }); configurator = new DataSeriesConfigurator(this, DataSeries.UseCase.RETURN_VOLATILITY); configurator.addListener(() -> updateChart()); DataSeriesChartLegend legend = new DataSeriesChartLegend(composite, configurator); updateTitle(Messages.LabelHistoricalReturnsAndVolatiltity + " (" + configurator.getConfigurationName() + ")"); //$NON-NLS-1$ //$NON-NLS-2$ chart.getTitle().setText(getTitle()); GridLayoutFactory.fillDefaults().numColumns(1).margins(0, 0).spacing(0, 0).applyTo(composite); GridDataFactory.fillDefaults().grab(true, true).applyTo(chart); GridDataFactory.fillDefaults().grab(true, false).align(SWT.CENTER, SWT.FILL).applyTo(legend); setChartSeries(); return composite; } @Override public void setFocus() { chart.adjustRange(); chart.setFocus(); } @Override public void reportingPeriodUpdated() { cache.clear(); updateChart(); } @Override public void notifyModelUpdated() { cache.clear(); updateChart(); } private void updateChart() { try { updateTitle(Messages.LabelHistoricalReturnsAndVolatiltity + " (" + configurator.getConfigurationName() //$NON-NLS-1$ + ")"); //$NON-NLS-1$ chart.suspendUpdate(true); chart.getTitle().setText(getTitle()); for (ISeries s : chart.getSeriesSet().getSeries()) chart.getSeriesSet().deleteSeries(s.getId()); setChartSeries(); chart.adjustRange(); } finally { chart.suspendUpdate(false); } chart.redraw(); } private void setChartSeries() { configurator.getSelectedDataSeries().forEach(series -> { PerformanceIndex index = cache.lookup(series, getReportingPeriod()); Volatility volatility = index.getVolatility(); ILineSeries lineSeries = chart.addScatterSeries(new double[] { volatility.getStandardDeviation() }, new double[] { index.getFinalAccumulatedPercentage() }, series.getLabel()); Color color = resources.createColor(series.getColor()); lineSeries.setLineColor(color); lineSeries.setSymbolColor(color); lineSeries.enableArea(series.isShowArea()); lineSeries.setLineStyle(series.getLineStyle()); }); } private final class ExportDropDown extends AbstractDropDown { private ExportDropDown(ToolBar toolBar) { super(toolBar, Messages.MenuExportData, Images.EXPORT.image(), SWT.NONE); } @Override public void menuAboutToShow(IMenuManager manager) { manager.add(new SimpleAction(Messages.MenuExportChartData, a -> { ScatterChartCSVExporter exporter = new ScatterChartCSVExporter(chart); exporter.setValueFormat(new DecimalFormat("0.##########%")); //$NON-NLS-1$ exporter.export(getTitle() + ".csv"); //$NON-NLS-1$ })); for (DataSeries series : configurator.getSelectedDataSeries()) manager.add(new SimpleAction(MessageFormat.format(Messages.LabelExport, series.getLabel()), a -> exportDataSeries(series))); manager.add(new Separator()); chart.exportMenuAboutToShow(manager, getTitle()); } private void exportDataSeries(DataSeries series) { AbstractCSVExporter exporter = new AbstractCSVExporter() { @Override protected void writeToFile(File file) throws IOException { PerformanceIndex index = cache.lookup(series, getReportingPeriod()); index.exportVolatilityData(file); } @Override protected Control getControl() { return ExportDropDown.this.getToolBar(); } }; exporter.export(getTitle() + "_" + series.getLabel() + ".csv"); //$NON-NLS-1$ //$NON-NLS-2$ } } }