package name.abuchen.portfolio.ui.views; import java.time.LocalDate; import java.time.Month; import java.time.format.TextStyle; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Locale; import org.eclipse.jface.action.Action; import org.eclipse.jface.action.ActionContributionItem; import org.eclipse.jface.action.IMenuListener; import org.eclipse.jface.action.IMenuManager; import org.eclipse.jface.action.Separator; import org.eclipse.jface.layout.TableColumnLayout; import org.eclipse.jface.viewers.ArrayContentProvider; import org.eclipse.jface.viewers.ColumnLabelProvider; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.viewers.TableViewer; import org.eclipse.swt.SWT; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Menu; import org.eclipse.swt.widgets.ToolBar; import org.swtchart.ISeries; import name.abuchen.portfolio.model.ConsumerPriceIndex; import name.abuchen.portfolio.money.Values; import name.abuchen.portfolio.ui.Images; import name.abuchen.portfolio.ui.Messages; import name.abuchen.portfolio.ui.util.Colors; import name.abuchen.portfolio.ui.util.chart.TimelineChart; import name.abuchen.portfolio.ui.util.chart.TimelineChartCSVExporter; import name.abuchen.portfolio.ui.util.viewers.Column; import name.abuchen.portfolio.ui.util.viewers.ColumnEditingSupport; import name.abuchen.portfolio.ui.util.viewers.ColumnEditingSupport.ModificationListener; import name.abuchen.portfolio.ui.util.viewers.ColumnViewerSorter; import name.abuchen.portfolio.ui.util.viewers.MonthEditingSupport; import name.abuchen.portfolio.ui.util.viewers.ShowHideColumnHelper; import name.abuchen.portfolio.ui.util.viewers.ValueEditingSupport; public class ConsumerPriceIndexListView extends AbstractListView implements ModificationListener { private TableViewer indices; private TimelineChart chart; @Override protected String getDefaultTitle() { return Messages.LabelConsumerPriceIndex; } protected void addButtons(ToolBar toolBar) { super.addButtons(toolBar); addExportButton(toolBar); } private void addExportButton(ToolBar toolBar) { Action export = new Action() { private Menu menu; @Override public void run() { if (menu == null) { menu = createContextMenu(getActiveShell(), new IMenuListener() { @Override public void menuAboutToShow(IMenuManager manager) { exportMenuAboutToShow(manager); } }); } menu.setVisible(true); } }; export.setImageDescriptor(Images.EXPORT.descriptor()); export.setToolTipText(Messages.MenuExportData); new ActionContributionItem(export).fill(toolBar, -1); } private void exportMenuAboutToShow(IMenuManager manager) { manager.add(new Action(Messages.MenuExportChartData) { @Override public void run() { new TimelineChartCSVExporter(chart).export(getTitle() + ".csv"); //$NON-NLS-1$ } }); manager.add(new Separator()); chart.exportMenuAboutToShow(manager, getTitle()); } @Override public void setFocus() { chart.getAxisSet().adjustRange(); super.setFocus(); } @Override public void notifyModelUpdated() { indices.setInput(getClient().getConsumerPriceIndices()); refreshChart(); } @Override public void onModified(Object element, Object newValue, Object oldValue) { markDirty(); refreshChart(); } @Override protected void createTopTable(Composite parent) { Composite container = new Composite(parent, SWT.NONE); TableColumnLayout layout = new TableColumnLayout(); container.setLayout(layout); indices = new TableViewer(container, SWT.FULL_SELECTION); ColumnEditingSupport.prepare(indices); ShowHideColumnHelper support = new ShowHideColumnHelper( ConsumerPriceIndexListView.class.getSimpleName() + "@bottom", getPreferenceStore(), indices, //$NON-NLS-1$ layout); Column column = new Column(Messages.ColumnYear, SWT.None, 80); column.setLabelProvider(new ColumnLabelProvider() { @Override public String getText(Object element) { return String.valueOf(((ConsumerPriceIndex) element).getYear()); } }); ColumnViewerSorter.create(ConsumerPriceIndex.class, "year", "month").attachTo(column, SWT.DOWN); //$NON-NLS-1$ //$NON-NLS-2$ new ValueEditingSupport(ConsumerPriceIndex.class, "year", Values.Year).addListener(this).attachTo(column); //$NON-NLS-1$ support.addColumn(column); column = new Column(Messages.ColumnMonth, SWT.None, 80); column.setLabelProvider(new ColumnLabelProvider() { @Override public String getText(Object element) { int month = ((ConsumerPriceIndex) element).getMonth(); return Month.of(month).getDisplayName(TextStyle.FULL, Locale.getDefault()); } }); ColumnViewerSorter.create(ConsumerPriceIndex.class, "month", "year").attachTo(column); //$NON-NLS-1$ //$NON-NLS-2$ new MonthEditingSupport(ConsumerPriceIndex.class, "month").addListener(this).attachTo(column); //$NON-NLS-1$ support.addColumn(column); column = new Column(Messages.ColumnIndex, SWT.RIGHT, 80); column.setLabelProvider(new ColumnLabelProvider() { @Override public String getText(Object element) { return Values.Index.format(((ConsumerPriceIndex) element).getIndex()); } }); ColumnViewerSorter.create(ConsumerPriceIndex.class, "index").attachTo(column); //$NON-NLS-1$ new ValueEditingSupport(ConsumerPriceIndex.class, "index", Values.Index).addListener(this).attachTo(column); //$NON-NLS-1$ support.addColumn(column); support.createColumns(); indices.getTable().setHeaderVisible(true); indices.getTable().setLinesVisible(true); indices.setContentProvider(ArrayContentProvider.getInstance()); indices.setInput(getClient().getConsumerPriceIndices()); indices.refresh(); hookContextMenu(indices.getTable(), new IMenuListener() { public void menuAboutToShow(IMenuManager manager) { fillContextMenu(manager); } }); } private void fillContextMenu(IMenuManager manager) { manager.add(new Action(Messages.ConsumerPriceIndexMenuDelete) { @Override public void run() { ConsumerPriceIndex index = (ConsumerPriceIndex) ((IStructuredSelection) indices.getSelection()) .getFirstElement(); if (index == null) return; getClient().removeConsumerPriceIndex(index); markDirty(); indices.setInput(getClient().getConsumerPriceIndices()); refreshChart(); } }); manager.add(new Action(Messages.ConsumerPriceIndexMenuAdd) { @Override public void run() { ConsumerPriceIndex index = new ConsumerPriceIndex(); LocalDate now = LocalDate.now(); index.setYear(now.getYear()); index.setMonth(now.getMonthValue()); getClient().addConsumerPriceIndex(index); markDirty(); indices.setInput(getClient().getConsumerPriceIndices()); indices.editElement(index, 0); refreshChart(); } }); } @Override protected void createBottomTable(Composite parent) { chart = new TimelineChart(parent); chart.getTitle().setText(Messages.LabelConsumerPriceIndex); chart.getToolTip().setDateFormat("%1$tB %1$tY"); //$NON-NLS-1$ refreshChart(); } private void refreshChart() { try { chart.suspendUpdate(true); for (ISeries s : chart.getSeriesSet().getSeries()) chart.getSeriesSet().deleteSeries(s.getId()); if (getClient().getConsumerPriceIndices() == null || getClient().getConsumerPriceIndices().isEmpty()) return; List<ConsumerPriceIndex> indices = new ArrayList<ConsumerPriceIndex>(getClient().getConsumerPriceIndices()); Collections.sort(indices, new ConsumerPriceIndex.ByDate()); LocalDate[] dates = new LocalDate[indices.size()]; double[] cpis = new double[indices.size()]; int ii = 0; for (ConsumerPriceIndex index : indices) { dates[ii] = LocalDate.of(index.getYear(), index.getMonth(), 1); cpis[ii] = (double) index.getIndex() / Values.Index.divider(); ii++; } chart.addDateSeries(dates, cpis, Colors.CPI, Messages.LabelConsumerPriceIndex); chart.adjustRange(); } finally { chart.suspendUpdate(false); chart.redraw(); } } }