package name.abuchen.portfolio.ui.views; import java.text.MessageFormat; import java.util.ArrayList; import java.util.Collections; import java.util.List; import javax.inject.Inject; 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.MenuManager; import org.eclipse.jface.action.Separator; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.jface.layout.TableColumnLayout; import org.eclipse.jface.viewers.ArrayContentProvider; import org.eclipse.jface.viewers.ColumnLabelProvider; import org.eclipse.jface.viewers.ISelectionChangedListener; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.viewers.SelectionChangedEvent; import org.eclipse.jface.viewers.StructuredSelection; import org.eclipse.jface.viewers.TableViewer; import org.eclipse.swt.SWT; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.ToolBar; import name.abuchen.portfolio.model.Account; import name.abuchen.portfolio.model.InvestmentPlan; import name.abuchen.portfolio.model.PortfolioTransaction; import name.abuchen.portfolio.model.Security; import name.abuchen.portfolio.money.CurrencyConverterImpl; import name.abuchen.portfolio.money.ExchangeRateProviderFactory; import name.abuchen.portfolio.money.Money; import name.abuchen.portfolio.money.Values; import name.abuchen.portfolio.ui.Images; import name.abuchen.portfolio.ui.Messages; import name.abuchen.portfolio.ui.dialogs.transactions.InvestmentPlanDialog; import name.abuchen.portfolio.ui.dialogs.transactions.InvestmentPlanModel; import name.abuchen.portfolio.ui.dialogs.transactions.OpenDialogAction; import name.abuchen.portfolio.ui.util.AbstractDropDown; 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.DateEditingSupport; import name.abuchen.portfolio.ui.util.viewers.ListEditingSupport; import name.abuchen.portfolio.ui.util.viewers.ShowHideColumnHelper; import name.abuchen.portfolio.ui.util.viewers.ValueEditingSupport; import name.abuchen.portfolio.ui.views.columns.NameColumn; import name.abuchen.portfolio.ui.views.columns.NoteColumn; public class InvestmentPlanListView extends AbstractListView implements ModificationListener { private TableViewer plans; private PortfolioTransactionsViewer transactions; private ShowHideColumnHelper planColumns; @Inject private ExchangeRateProviderFactory factory; @Override protected String getDefaultTitle() { return Messages.LabelInvestmentPlans; } @Override public void notifyModelUpdated() { plans.setSelection(plans.getSelection()); } @Override public void onModified(Object element, Object newValue, Object oldValue) { InvestmentPlan plan = (InvestmentPlan) element; if (plan.getAccount() != null && plan.getAccount().equals(InvestmentPlanModel.DELIVERY)) plan.setAccount(null); markDirty(); } @Override protected void addButtons(ToolBar toolBar) { addNewInvestmentPlanButton(toolBar); addConfigButton(toolBar); } private void addNewInvestmentPlanButton(ToolBar toolBar) { Action action = new OpenDialogAction(this, Messages.InvestmentPlanMenuCreate) // .type(InvestmentPlanDialog.class).onSuccess(d -> { markDirty(); plans.setInput(getClient().getPlans()); }); action.setImageDescriptor(Images.PLUS.descriptor()); action.setToolTipText(Messages.InvestmentPlanMenuCreate); new ActionContributionItem(action).fill(toolBar, -1); } private void addConfigButton(final ToolBar toolBar) { new AbstractDropDown(toolBar, Messages.MenuShowHideColumns, Images.CONFIG.image(), SWT.NONE) { @Override public void menuAboutToShow(IMenuManager manager) { MenuManager m = new MenuManager(Messages.LabelInvestmentPlans); planColumns.menuAboutToShow(m); manager.add(m); m = new MenuManager(Messages.LabelTransactions); transactions.getColumnSupport().menuAboutToShow(m); manager.add(m); } }; } @Override protected void createTopTable(Composite parent) { Composite container = new Composite(parent, SWT.NONE); TableColumnLayout layout = new TableColumnLayout(); container.setLayout(layout); plans = new TableViewer(container, SWT.FULL_SELECTION); ColumnEditingSupport.prepare(plans); planColumns = new ShowHideColumnHelper(InvestmentPlanListView.class.getSimpleName() + "@top", //$NON-NLS-1$ getPreferenceStore(), plans, layout); addColumns(planColumns); planColumns.createColumns(); plans.getTable().setHeaderVisible(true); plans.getTable().setLinesVisible(true); plans.setContentProvider(ArrayContentProvider.getInstance()); plans.setInput(getClient().getPlans()); plans.addSelectionChangedListener(new ISelectionChangedListener() { public void selectionChanged(SelectionChangedEvent event) { InvestmentPlan plan = (InvestmentPlan) ((IStructuredSelection) event.getSelection()).getFirstElement(); if (plan != null) transactions.setInput(plan.getPortfolio(), plan.getTransactions()); else transactions.setInput(null, null); transactions.refresh(); } }); hookContextMenu(plans.getTable(), new IMenuListener() { public void menuAboutToShow(IMenuManager manager) { fillPlansContextMenu(manager); } }); } private void addColumns(ShowHideColumnHelper support) { Column column = new NameColumn("0", Messages.ColumnName, SWT.None, 100); //$NON-NLS-1$ column.getEditingSupport().addListener(this); support.addColumn(column); column = new Column(Messages.ColumnSecurity, SWT.NONE, 250); column.setLabelProvider(new ColumnLabelProvider() { @Override public String getText(Object e) { return ((InvestmentPlan) e).getSecurity().getName(); } @Override public Image getImage(Object element) { return Images.SECURITY.image(); } }); ColumnViewerSorter.create(Security.class, "name").attachTo(column); //$NON-NLS-1$ List<Security> securities = new ArrayList<Security>(getClient().getSecurities()); Collections.sort(securities, new Security.ByName()); new ListEditingSupport(InvestmentPlan.class, "security", securities).addListener(this).attachTo(column); //$NON-NLS-1$ support.addColumn(column); column = new Column(Messages.ColumnPortfolio, SWT.None, 120); column.setLabelProvider(new ColumnLabelProvider() { @Override public String getText(Object e) { return ((InvestmentPlan) e).getPortfolio().getName(); } @Override public Image getImage(Object element) { return Images.PORTFOLIO.image(); } }); ColumnViewerSorter.create(InvestmentPlan.class, "portfolio").attachTo(column); //$NON-NLS-1$ new ListEditingSupport(InvestmentPlan.class, "portfolio", getClient().getActivePortfolios()).addListener(this) //$NON-NLS-1$ .attachTo(column); support.addColumn(column); column = new Column(Messages.ColumnAccount, SWT.None, 120); column.setLabelProvider(new ColumnLabelProvider() { @Override public String getText(Object e) { InvestmentPlan plan = (InvestmentPlan) e; return plan.getAccount() != null ? plan.getAccount().getName() : Messages.InvestmentPlanOptionDelivery; } @Override public Image getImage(Object e) { InvestmentPlan plan = (InvestmentPlan) e; return plan.getAccount() != null ? Images.ACCOUNT.image() : null; } }); ColumnViewerSorter.create(Account.class, "name").attachTo(column); //$NON-NLS-1$ List<Account> accounts = new ArrayList<Account>(); accounts.add(InvestmentPlanModel.DELIVERY); accounts.addAll(getClient().getAccounts()); new ListEditingSupport(InvestmentPlan.class, "account", accounts).addListener(this).attachTo(column); //$NON-NLS-1$ support.addColumn(column); column = new Column(Messages.ColumnStartDate, SWT.None, 80); column.setLabelProvider(new ColumnLabelProvider() { @Override public String getText(Object e) { return Values.Date.format(((InvestmentPlan) e).getStart()); } }); ColumnViewerSorter.create(InvestmentPlan.class, "start").attachTo(column); //$NON-NLS-1$ new DateEditingSupport(InvestmentPlan.class, "start").addListener(this).attachTo(column); //$NON-NLS-1$ support.addColumn(column); column = new Column(Messages.ColumnInterval, SWT.None, 80); column.setLabelProvider(new ColumnLabelProvider() { @Override public String getText(Object e) { return MessageFormat.format(Messages.InvestmentPlanIntervalLabel, ((InvestmentPlan) e).getInterval()); } }); ColumnViewerSorter.create(InvestmentPlan.class, "interval").attachTo(column); //$NON-NLS-1$ List<Integer> available = new ArrayList<Integer>(); for (int ii = 1; ii <= 12; ii++) available.add(ii); new ListEditingSupport(InvestmentPlan.class, "interval", available).addListener(this).attachTo(column); //$NON-NLS-1$ support.addColumn(column); column = new Column(Messages.ColumnAmount, SWT.RIGHT, 80); column.setLabelProvider(new ColumnLabelProvider() { @Override public String getText(Object e) { InvestmentPlan plan = (InvestmentPlan) e; return Values.Money.format(Money.of(plan.getCurrencyCode(), plan.getAmount())); } }); ColumnViewerSorter.create(InvestmentPlan.class, "amount").attachTo(column); //$NON-NLS-1$ new ValueEditingSupport(InvestmentPlan.class, "amount", Values.Amount).addListener(this).attachTo(column); //$NON-NLS-1$ support.addColumn(column); column = new Column(Messages.ColumnFees, SWT.RIGHT, 80); column.setLabelProvider(new ColumnLabelProvider() { @Override public String getText(Object e) { InvestmentPlan plan = (InvestmentPlan) e; return Values.Money.format(Money.of(plan.getCurrencyCode(), plan.getFees())); } }); ColumnViewerSorter.create(InvestmentPlan.class, "fees").attachTo(column); //$NON-NLS-1$ new ValueEditingSupport(InvestmentPlan.class, "fees", Values.Amount).addListener(this).attachTo(column); //$NON-NLS-1$ support.addColumn(column); column = new NoteColumn(); column.getEditingSupport().addListener(this); column.setVisible(false); support.addColumn(column); } private void fillPlansContextMenu(IMenuManager manager) { final InvestmentPlan plan = (InvestmentPlan) ((IStructuredSelection) plans.getSelection()).getFirstElement(); if (plan == null) return; manager.add(new Action(Messages.InvestmentPlanMenuGenerateTransactions) { @Override public void run() { CurrencyConverterImpl converter = new CurrencyConverterImpl(factory, getClient().getBaseCurrency()); List<PortfolioTransaction> latest = plan.generateTransactions(converter); if (latest.isEmpty()) { MessageDialog.openInformation(getActiveShell(), Messages.LabelInfo, MessageFormat.format(Messages.InvestmentPlanInfoNoTransactionsGenerated, Values.Date.format(plan.getDateOfNextTransactionToBeGenerated()))); } else { markDirty(); plans.refresh(); transactions.markTransactions(latest); transactions.setInput(plan.getPortfolio(), plan.getTransactions()); } } }); manager.add(new Separator()); new OpenDialogAction(this, Messages.MenuEditInvestmentPlan) // .type(InvestmentPlanDialog.class, d -> d.setPlan(plan)) // .onSuccess(d -> { markDirty(); plans.setInput(getClient().getPlans()); }).addTo(manager); manager.add(new Action(Messages.InvestmentPlanMenuDelete) { @Override public void run() { getClient().removePlan(plan); markDirty(); plans.setInput(getClient().getPlans()); transactions.setInput(null, null); } }); } @Override protected void createBottomTable(Composite parent) { transactions = new PortfolioTransactionsViewer(parent, this); transactions.setFullContextMenu(false); if (!getClient().getPlans().isEmpty()) plans.setSelection(new StructuredSelection(plans.getElementAt(0)), true); } }