package name.abuchen.portfolio.ui.views;
import java.text.MessageFormat;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
import java.util.function.BiFunction;
import java.util.stream.Collectors;
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.dialogs.Dialog;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.layout.TableColumnLayout;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.jface.resource.LocalResourceManager;
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.TableViewer;
import org.eclipse.jface.viewers.ViewerFilter;
import org.eclipse.jface.wizard.WizardDialog;
import org.eclipse.swt.SWT;
import org.eclipse.swt.dnd.DND;
import org.eclipse.swt.dnd.Transfer;
import org.eclipse.swt.events.KeyAdapter;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.Shell;
import name.abuchen.portfolio.model.AccountTransaction;
import name.abuchen.portfolio.model.Client;
import name.abuchen.portfolio.model.LatestSecurityPrice;
import name.abuchen.portfolio.model.PortfolioTransaction;
import name.abuchen.portfolio.model.Security;
import name.abuchen.portfolio.model.SecurityPrice;
import name.abuchen.portfolio.model.Taxonomy;
import name.abuchen.portfolio.model.Watchlist;
import name.abuchen.portfolio.money.Values;
import name.abuchen.portfolio.online.QuoteFeed;
import name.abuchen.portfolio.snapshot.ReportingPeriod;
import name.abuchen.portfolio.ui.AbstractFinanceView;
import name.abuchen.portfolio.ui.Images;
import name.abuchen.portfolio.ui.Messages;
import name.abuchen.portfolio.ui.UpdateQuotesJob;
import name.abuchen.portfolio.ui.dialogs.transactions.AccountTransactionDialog;
import name.abuchen.portfolio.ui.dialogs.transactions.OpenDialogAction;
import name.abuchen.portfolio.ui.dialogs.transactions.SecurityTransactionDialog;
import name.abuchen.portfolio.ui.dialogs.transactions.SecurityTransferDialog;
import name.abuchen.portfolio.ui.dnd.SecurityDragListener;
import name.abuchen.portfolio.ui.dnd.SecurityTransfer;
import name.abuchen.portfolio.ui.util.BookmarkMenu;
import name.abuchen.portfolio.ui.util.Colors;
import name.abuchen.portfolio.ui.util.viewers.BooleanEditingSupport;
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.NumberColorLabelProvider;
import name.abuchen.portfolio.ui.util.viewers.OptionLabelProvider;
import name.abuchen.portfolio.ui.util.viewers.ReportingPeriodColumnOptions;
import name.abuchen.portfolio.ui.util.viewers.ShowHideColumnHelper;
import name.abuchen.portfolio.ui.util.viewers.StringEditingSupport;
import name.abuchen.portfolio.ui.views.columns.AttributeColumn;
import name.abuchen.portfolio.ui.views.columns.CurrencyColumn;
import name.abuchen.portfolio.ui.views.columns.IsinColumn;
import name.abuchen.portfolio.ui.views.columns.NoteColumn;
import name.abuchen.portfolio.ui.views.columns.TaxonomyColumn;
import name.abuchen.portfolio.ui.wizards.security.EditSecurityDialog;
import name.abuchen.portfolio.ui.wizards.splits.StockSplitWizard;
public final class SecuritiesTable implements ModificationListener
{
private AbstractFinanceView view;
private Watchlist watchlist;
private Menu contextMenu;
private TableViewer securities;
private ShowHideColumnHelper support;
private LocalResourceManager resources;
private Color warningColor;
public SecuritiesTable(Composite parent, AbstractFinanceView view)
{
this.view = view;
Composite container = new Composite(parent, SWT.NONE);
TableColumnLayout layout = new TableColumnLayout();
container.setLayout(layout);
this.resources = new LocalResourceManager(JFaceResources.getResources(), container);
this.warningColor = resources.createColor(Colors.WARNING.swt());
this.securities = new TableViewer(container, SWT.FULL_SELECTION | SWT.MULTI);
ColumnEditingSupport.prepare(securities);
support = new ShowHideColumnHelper(SecuritiesTable.class.getName(), getClient(), view.getPreferenceStore(),
securities, layout);
addMasterDataColumns();
addColumnLatestPrice();
addDeltaColumn();
addColumnDateOfLatestPrice();
addColumnDateOfLatestHistoricalPrice();
addQuoteDeltaColumn();
for (Taxonomy taxonomy : getClient().getTaxonomies())
{
Column column = new TaxonomyColumn(taxonomy);
column.setVisible(false);
support.addColumn(column);
}
addAttributeColumns();
support.createColumns();
securities.getTable().setHeaderVisible(true);
securities.getTable().setLinesVisible(true);
securities.setContentProvider(ArrayContentProvider.getInstance());
securities.addDragSupport(DND.DROP_MOVE, //
new Transfer[] { SecurityTransfer.getTransfer() }, //
new SecurityDragListener(securities));
hookKeyListener();
securities.refresh();
hookContextMenu();
}
private void addMasterDataColumns()
{
Column column = new Column("0", Messages.ColumnName, SWT.LEFT, 400); //$NON-NLS-1$
column.setLabelProvider(new ColumnLabelProvider()
{
@Override
public String getText(Object e)
{
return ((Security) e).getName();
}
@Override
public Image getImage(Object e)
{
return ((Security) e).isRetired() ? Images.SECURITY_RETIRED.image() : Images.SECURITY.image();
}
});
ColumnViewerSorter.create(Security.class, "name").attachTo(column, SWT.DOWN); //$NON-NLS-1$
new StringEditingSupport(Security.class, "name").setMandatory(true).addListener(this).attachTo(column); //$NON-NLS-1$
support.addColumn(column);
column = new NoteColumn();
column.getEditingSupport().addListener(this);
support.addColumn(column);
column = new IsinColumn("1"); //$NON-NLS-1$
column.getEditingSupport().addListener(this);
support.addColumn(column);
column = new Column("2", Messages.ColumnTicker, SWT.LEFT, 80); //$NON-NLS-1$
column.setLabelProvider(new ColumnLabelProvider()
{
@Override
public String getText(Object e)
{
return ((Security) e).getTickerSymbol();
}
});
column.setSorter(ColumnViewerSorter.create(Security.class, "tickerSymbol")); //$NON-NLS-1$
new StringEditingSupport(Security.class, "tickerSymbol").addListener(this).attachTo(column); //$NON-NLS-1$
support.addColumn(column);
column = new Column("7", Messages.ColumnWKN, SWT.LEFT, 60); //$NON-NLS-1$
column.setLabelProvider(new ColumnLabelProvider()
{
@Override
public String getText(Object e)
{
return ((Security) e).getWkn();
}
});
column.setSorter(ColumnViewerSorter.create(Security.class, "wkn")); //$NON-NLS-1$
new StringEditingSupport(Security.class, "wkn").addListener(this).attachTo(column); //$NON-NLS-1$
column.setVisible(false);
support.addColumn(column);
column = new CurrencyColumn();
column.setVisible(false);
support.addColumn(column);
column = new Column("8", Messages.ColumnRetired, SWT.LEFT, 40); //$NON-NLS-1$
column.setLabelProvider(new ColumnLabelProvider()
{
@Override
public String getText(Object e)
{
return ""; //$NON-NLS-1$
}
@Override
public Image getImage(Object e)
{
return ((Security) e).isRetired() ? Images.CHECK.image() : null;
}
});
column.setSorter(ColumnViewerSorter.create(Security.class, "retired")); //$NON-NLS-1$
new BooleanEditingSupport(Security.class, "retired").addListener(this).attachTo(column); //$NON-NLS-1$
column.setVisible(false);
support.addColumn(column);
}
private void addColumnLatestPrice() // NOSONAR
{
Column column = new Column("4", Messages.ColumnLatest, SWT.RIGHT, 60); //$NON-NLS-1$
column.setMenuLabel(Messages.ColumnLatest_MenuLabel);
column.setLabelProvider(new ColumnLabelProvider()
{
@Override
public String getText(Object e)
{
Security security = (Security) e;
SecurityPrice latest = security.getSecurityPrice(LocalDate.now());
if (latest == null)
return null;
if (security.getCurrencyCode() == null)
return Values.Quote.format(latest.getValue());
else
return Values.Quote.format(security.getCurrencyCode(), latest.getValue(),
getClient().getBaseCurrency());
}
});
column.setSorter(ColumnViewerSorter.create((o1, o2) -> {
SecurityPrice p1 = ((Security) o1).getSecurityPrice(LocalDate.now());
SecurityPrice p2 = ((Security) o2).getSecurityPrice(LocalDate.now());
if (p1 == null)
return p2 == null ? 0 : -1;
if (p2 == null)
return 1;
long v1 = p1.getValue();
long v2 = p2.getValue();
return v1 > v2 ? 1 : v1 == v2 ? 0 : -1;
}));
support.addColumn(column);
}
private void addDeltaColumn() // NOSONAR
{
Column column;
column = new Column("5", Messages.ColumnChangeOnPrevious, SWT.RIGHT, 60); //$NON-NLS-1$
column.setMenuLabel(Messages.ColumnChangeOnPrevious_MenuLabel);
column.setLabelProvider(new NumberColorLabelProvider<>(Values.Percent2, element -> {
SecurityPrice price = ((Security) element).getSecurityPrice(LocalDate.now());
if (!(price instanceof LatestSecurityPrice))
return null;
LatestSecurityPrice latest = (LatestSecurityPrice) price;
return (latest.getValue() - latest.getPreviousClose()) / (double) latest.getPreviousClose();
}));
column.setSorter(ColumnViewerSorter.create((o1, o2) -> { // NOSONAR
SecurityPrice p1 = ((Security) o1).getSecurityPrice(LocalDate.now());
SecurityPrice p2 = ((Security) o2).getSecurityPrice(LocalDate.now());
if (!(p1 instanceof LatestSecurityPrice))
p1 = null;
if (!(p2 instanceof LatestSecurityPrice))
p2 = null;
if (p1 == null)
return p2 == null ? 0 : -1;
if (p2 == null)
return 1;
LatestSecurityPrice l1 = (LatestSecurityPrice) p1;
LatestSecurityPrice l2 = (LatestSecurityPrice) p2;
double v1 = ((double) (l1.getValue() - l1.getPreviousClose())) / l1.getPreviousClose() * 100;
double v2 = ((double) (l2.getValue() - l2.getPreviousClose())) / l2.getPreviousClose() * 100;
return Double.compare(v1, v2);
}));
support.addColumn(column);
}
private void addColumnDateOfLatestPrice() // NOSONAR
{
Column column;
column = new Column("9", Messages.ColumnLatestDate, SWT.LEFT, 80); //$NON-NLS-1$
column.setMenuLabel(Messages.ColumnLatestDate_MenuLabel);
column.setLabelProvider(new ColumnLabelProvider()
{
@Override
public String getText(Object element)
{
SecurityPrice latest = ((Security) element).getSecurityPrice(LocalDate.now());
return latest != null ? Values.Date.format(latest.getTime()) : null;
}
@Override
public Color getBackground(Object element)
{
Security security = (Security) element;
SecurityPrice latest = security.getSecurityPrice(LocalDate.now());
if (latest == null)
return null;
String feed = security.getLatestFeed() != null ? security.getLatestFeed() : security.getFeed();
if (QuoteFeed.MANUAL.equals(feed))
return null;
LocalDate sevenDaysAgo = LocalDate.now().minusDays(7);
return latest.getTime().isBefore(sevenDaysAgo) ? warningColor : null;
}
});
column.setSorter(ColumnViewerSorter.create((o1, o2) -> {
SecurityPrice p1 = ((Security) o1).getSecurityPrice(LocalDate.now());
SecurityPrice p2 = ((Security) o2).getSecurityPrice(LocalDate.now());
if (p1 == null)
return p2 == null ? 0 : -1;
if (p2 == null)
return 1;
return p1.getTime().compareTo(p2.getTime());
}));
support.addColumn(column);
}
private void addColumnDateOfLatestHistoricalPrice() // NOSONAR
{
Column column = new Column("10", Messages.ColumnLatestHistoricalDate, SWT.LEFT, 80); //$NON-NLS-1$
column.setMenuLabel(Messages.ColumnLatestHistoricalDate_MenuLabel);
column.setLabelProvider(new ColumnLabelProvider() // NOSONAR
{
@Override
public String getText(Object element)
{
List<SecurityPrice> prices = ((Security) element).getPrices();
if (prices.isEmpty())
return null;
SecurityPrice latest = prices.get(prices.size() - 1);
return latest != null ? Values.Date.format(latest.getTime()) : null;
}
@Override
public Color getBackground(Object element)
{
Security security = (Security) element;
List<SecurityPrice> prices = security.getPrices();
if (prices.isEmpty())
return null;
if (QuoteFeed.MANUAL.equals(security.getFeed()))
return null;
SecurityPrice latest = prices.get(prices.size() - 1);
if (!((Security) element).isRetired() && latest.getTime().isBefore(LocalDate.now().minusDays(7)))
return warningColor;
else
return null;
}
});
column.setSorter(ColumnViewerSorter.create((o1, o2) -> {
List<SecurityPrice> prices1 = ((Security) o1).getPrices();
SecurityPrice p1 = prices1.isEmpty() ? null : prices1.get(prices1.size() - 1);
List<SecurityPrice> prices2 = ((Security) o2).getPrices();
SecurityPrice p2 = prices2.isEmpty() ? null : prices2.get(prices2.size() - 1);
if (p1 == null)
return p2 == null ? 0 : -1;
if (p2 == null)
return 1;
return p1.getTime().compareTo(p2.getTime());
}));
support.addColumn(column);
}
private void addQuoteDeltaColumn() // NOSONAR
{
// create a modifiable copy as all menus share the same list of
// reporting periods
List<ReportingPeriod> options = new ArrayList<>(view.getPart().loadReportingPeriods());
BiFunction<Object, ReportingPeriod, Double> valueProvider = (element, option) -> {
Security security = (Security) element;
SecurityPrice latest = security.getSecurityPrice(option.getEndDate());
SecurityPrice previous = security.getSecurityPrice(option.getStartDate());
if (latest == null || previous == null)
return null;
if (previous.getValue() == 0)
return null;
if (previous.getTime().isAfter(option.getStartDate()))
return null;
return new Double((latest.getValue() - previous.getValue()) / (double) previous.getValue());
};
Column column = new Column("delta-w-period", Messages.ColumnQuoteChange, SWT.RIGHT, 80); //$NON-NLS-1$
column.setOptions(new ReportingPeriodColumnOptions(Messages.ColumnQuoteChange_Option, options));
column.setDescription(Messages.ColumnQuoteChange_Description);
column.setLabelProvider(new QuoteReportingPeriodLabelProvider(valueProvider));
column.setVisible(false);
column.setSorter(ColumnViewerSorter.create((o1, o2) -> {
ReportingPeriod option = (ReportingPeriod) ColumnViewerSorter.SortingContext.getColumnOption();
Double v1 = valueProvider.apply(o1, option);
Double v2 = valueProvider.apply(o2, option);
if (v1 == null && v2 == null)
return 0;
else if (v1 == null)
return -1;
else if (v2 == null)
return 1;
return Double.compare(v1.doubleValue(), v2.doubleValue());
}));
support.addColumn(column);
}
private void addAttributeColumns()
{
getClient().getSettings() //
.getAttributeTypes() //
.filter(a -> a.supports(Security.class)) //
.forEach(attribute -> {
Column column = new AttributeColumn(attribute);
column.setVisible(false);
column.getEditingSupport().addListener(this);
support.addColumn(column);
});
}
public void addSelectionChangedListener(ISelectionChangedListener listener)
{
this.securities.addSelectionChangedListener(listener);
}
public void addFilter(ViewerFilter filter)
{
this.securities.addFilter(filter);
}
public void setInput(List<Security> securities)
{
this.securities.setInput(securities);
this.watchlist = null;
}
public void setInput(Watchlist watchlist)
{
this.securities.setInput(watchlist.getSecurities());
this.watchlist = watchlist;
}
public void refresh(Security security)
{
this.securities.refresh(security, true);
}
public void refresh()
{
try
{
securities.getControl().setRedraw(false);
securities.refresh();
}
finally
{
securities.getControl().setRedraw(true);
}
}
@Override
public void onModified(Object element, Object newValue, Object oldValue)
{
markDirty();
}
public void updateQuotes(Security security)
{
new UpdateQuotesJob(getClient(), security).schedule();
}
public TableViewer getTableViewer()
{
return securities;
}
public ShowHideColumnHelper getColumnHelper()
{
return support;
}
//
// private
//
private Client getClient()
{
return view.getClient();
}
private Shell getShell()
{
return securities.getTable().getShell();
}
private void markDirty()
{
view.markDirty();
}
private void hookKeyListener()
{
securities.getControl().addKeyListener(new KeyAdapter()
{
@Override
public void keyPressed(KeyEvent e)
{
if (e.keyCode == 'e' && e.stateMask == SWT.MOD1)
new EditSecurityAction().run();
}
});
}
private void hookContextMenu()
{
MenuManager menuMgr = new MenuManager("#PopupMenu"); //$NON-NLS-1$
menuMgr.setRemoveAllWhenShown(true);
menuMgr.addMenuListener(this::fillContextMenu);
contextMenu = menuMgr.createContextMenu(securities.getTable());
securities.getTable().setMenu(contextMenu);
securities.getTable().addDisposeListener(e -> {
if (contextMenu != null)
contextMenu.dispose();
});
}
private void fillContextMenu(IMenuManager manager)
{
IStructuredSelection selection = (IStructuredSelection) securities.getSelection();
if (selection.isEmpty())
return;
if (selection.size() == 1)
{
Security security = (Security) selection.getFirstElement();
// only if the security has a currency code, it can be bought
if (security.getCurrencyCode() != null)
fillTransactionContextMenu(manager, security);
manager.add(new EditSecurityAction());
manager.add(new Separator());
new QuotesContextMenu(this.view).menuAboutToShow(manager, security);
manager.add(new Separator());
manager.add(new BookmarkMenu(view.getPart(), security));
}
manager.add(new Separator());
if (watchlist == null)
{
manager.add(new DeleteSecurityAction(selection));
}
else
{
manager.add(new Action(MessageFormat.format(Messages.SecurityMenuRemoveFromWatchlist, watchlist.getName()))
{
@Override
public void run()
{
for (Object security : selection.toArray())
watchlist.getSecurities().remove(security);
markDirty();
securities.setInput(watchlist.getSecurities());
}
});
}
}
private void fillTransactionContextMenu(IMenuManager manager, Security security)
{
new OpenDialogAction(view, Messages.SecurityMenuBuy + "...") //$NON-NLS-1$
.type(SecurityTransactionDialog.class) //
.parameters(PortfolioTransaction.Type.BUY) //
.with(security) //
.onSuccess(d -> performFinish(security)) //
.addTo(manager);
new OpenDialogAction(view, Messages.SecurityMenuSell + "...") //$NON-NLS-1$
.type(SecurityTransactionDialog.class) //
.parameters(PortfolioTransaction.Type.SELL) //
.with(security) //
.onSuccess(d -> performFinish(security)) //
.addTo(manager);
new OpenDialogAction(view, Messages.SecurityMenuDividends + "...") //$NON-NLS-1$
.type(AccountTransactionDialog.class) //
.parameters(AccountTransaction.Type.DIVIDENDS) //
.with(security) //
.onSuccess(d -> performFinish(security)) //
.addTo(manager);
new OpenDialogAction(view, AccountTransaction.Type.TAX_REFUND + "...") //$NON-NLS-1$
.type(AccountTransactionDialog.class) //
.parameters(AccountTransaction.Type.TAX_REFUND) //
.with(security) //
.onSuccess(d -> performFinish(security)) //
.addTo(manager);
manager.add(new AbstractDialogAction(Messages.SecurityMenuStockSplit)
{
@Override
Dialog createDialog(Security security)
{
StockSplitWizard wizard = new StockSplitWizard(getClient(), security);
return new WizardDialog(getShell(), wizard);
}
});
if (view.getClient().getActivePortfolios().size() > 1)
{
manager.add(new Separator());
new OpenDialogAction(view, Messages.SecurityMenuTransfer) //
.type(SecurityTransferDialog.class) //
.with(security) //
.addTo(manager);
}
manager.add(new Separator());
new OpenDialogAction(view, PortfolioTransaction.Type.DELIVERY_INBOUND.toString() + "...") //$NON-NLS-1$
.type(SecurityTransactionDialog.class) //
.parameters(PortfolioTransaction.Type.DELIVERY_INBOUND) //
.with(security) //
.onSuccess(d -> performFinish(security)) //
.addTo(manager);
new OpenDialogAction(view, PortfolioTransaction.Type.DELIVERY_OUTBOUND.toString() + "...") //$NON-NLS-1$
.type(SecurityTransactionDialog.class) //
.parameters(PortfolioTransaction.Type.DELIVERY_OUTBOUND) //
.with(security) //
.onSuccess(d -> performFinish(security)) //
.addTo(manager);
manager.add(new Separator());
}
private void performFinish(Security security)
{
markDirty();
if (!securities.getControl().isDisposed())
{
securities.refresh(security, true);
securities.setSelection(securities.getSelection());
}
}
private final class DeleteSecurityAction extends Action
{
private IStructuredSelection selection;
private DeleteSecurityAction(IStructuredSelection selection)
{
super(Messages.SecurityMenuDeleteSecurity);
this.selection = selection;
}
@Override
public void run()
{
boolean isDirty = false;
List<Security> withTransactions = new ArrayList<>();
for (Object obj : selection.toArray())
{
Security security = (Security) obj;
if (!security.getTransactions(getClient()).isEmpty())
{
withTransactions.add(security);
}
else
{
getClient().removeSecurity(security);
isDirty = true;
}
}
if (!withTransactions.isEmpty())
{
String label = String.join(", ", //$NON-NLS-1$
withTransactions.stream().map(s -> s.getName()).collect(Collectors.toList()));
MessageDialog.openError(getShell(), Messages.MsgDeletionNotPossible,
MessageFormat.format(Messages.MsgDeletionNotPossibleDetail, label));
}
if (isDirty)
{
markDirty();
securities.setInput(getClient().getSecurities());
}
}
}
private abstract class AbstractDialogAction extends Action
{
public AbstractDialogAction(String text)
{
super(text);
}
@Override
public final void run()
{
Security security = (Security) ((IStructuredSelection) securities.getSelection()).getFirstElement();
if (security == null)
return;
Dialog dialog = createDialog(security);
if (dialog.open() == Dialog.OK)
performFinish(security);
}
protected void performFinish(Security security)
{
markDirty();
if (!securities.getControl().isDisposed())
{
// the check if the security gets filtered after the change.
// Since it is unknown which property of the security has
// been changed, filter.isFilterProperty(...) can't be used.
boolean areFiltersAffected = false;
for (ViewerFilter filter : securities.getFilters())
{
if (!filter.select(securities, security, security))
areFiltersAffected = true;
}
if (areFiltersAffected)
securities.refresh();
else
securities.refresh(security, true);
securities.setSelection(securities.getSelection());
}
}
abstract Dialog createDialog(Security security);
}
private final class EditSecurityAction extends AbstractDialogAction
{
private EditSecurityAction()
{
super(Messages.SecurityMenuEditSecurity);
setAccelerator(SWT.MOD1 | 'E');
}
@Override
Dialog createDialog(Security security)
{
return new EditSecurityDialog(getShell(), getClient(), security);
}
@Override
protected void performFinish(Security security)
{
super.performFinish(security);
updateQuotes(security);
}
}
private static final class QuoteReportingPeriodLabelProvider extends OptionLabelProvider<ReportingPeriod>
{
private BiFunction<Object, ReportingPeriod, Double> valueProvider;
public QuoteReportingPeriodLabelProvider(BiFunction<Object, ReportingPeriod, Double> valueProvider)
{
this.valueProvider = valueProvider;
}
@Override
public String getText(Object e, ReportingPeriod option)
{
Double value = valueProvider.apply(e, option);
if (value == null)
return null;
return String.format("%,.2f %%", value * 100); //$NON-NLS-1$
}
@Override
public Color getForeground(Object e, ReportingPeriod option)
{
Double value = valueProvider.apply(e, option);
if (value == null)
return null;
if (value.doubleValue() < 0)
return Display.getCurrent().getSystemColor(SWT.COLOR_DARK_RED);
else if (value.doubleValue() > 0)
return Display.getCurrent().getSystemColor(SWT.COLOR_DARK_GREEN);
else
return null;
}
@Override
public Image getImage(Object element, ReportingPeriod option)
{
Double value = valueProvider.apply(element, option);
if (value == null)
return null;
if (value.doubleValue() > 0)
return Images.GREEN_ARROW.image();
if (value.doubleValue() < 0)
return Images.RED_ARROW.image();
return null;
}
}
}