package name.abuchen.portfolio.ui.views; import static name.abuchen.portfolio.ui.util.SWTHelper.EMPTY_LABEL; import static name.abuchen.portfolio.ui.util.SWTHelper.clearLabel; import static name.abuchen.portfolio.ui.util.SWTHelper.dateWidth; import static name.abuchen.portfolio.ui.util.SWTHelper.placeBelow; import java.text.MessageFormat; import java.util.ArrayList; import java.util.List; import org.eclipse.jface.layout.GridDataFactory; import org.eclipse.jface.layout.GridLayoutFactory; import org.eclipse.jface.resource.FontDescriptor; 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.Font; import org.eclipse.swt.layout.FormAttachment; import org.eclipse.swt.layout.FormData; import org.eclipse.swt.layout.FormLayout; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Label; import name.abuchen.portfolio.model.Classification; import name.abuchen.portfolio.model.Classification.Assignment; import name.abuchen.portfolio.model.Client; import name.abuchen.portfolio.model.LatestSecurityPrice; import name.abuchen.portfolio.model.Security; import name.abuchen.portfolio.model.Taxonomy; import name.abuchen.portfolio.model.Taxonomy.Visitor; import name.abuchen.portfolio.money.Values; import name.abuchen.portfolio.ui.Messages; import name.abuchen.portfolio.ui.PortfolioPlugin; import name.abuchen.portfolio.ui.util.Colors; public class SecurityDetailsViewer { private abstract static class SecurityFacet { private Font boldFont; private Color color; SecurityFacet(Font boldFont, Color color) { this.boldFont = boldFont; this.color = color; } abstract Control createViewControl(Composite parent, Client client); abstract void setInput(Security security); protected Label createHeading(Composite parent, String text) { Label heading = new Label(parent, SWT.NONE); heading.setText(text); heading.setFont(boldFont); heading.setForeground(color); return heading; } protected void below(Label referenceItem, Label value) { FormData data; data = new FormData(); data.top = new FormAttachment(referenceItem, 5); data.left = new FormAttachment(referenceItem, 0, SWT.LEFT); data.right = new FormAttachment(100); value.setLayoutData(data); } protected String escape(String label) { return label != null ? label.replaceAll("&", "&&") : EMPTY_LABEL; //$NON-NLS-1$ //$NON-NLS-2$ } protected String nonNullString(String label) { return label != null ? label : EMPTY_LABEL; } } private static class MasterDataFacet extends SecurityFacet { private Label valueName; private Label valueISIN; private Label valueTickerSymbol; public MasterDataFacet(Font boldFont, Color color) { super(boldFont, color); } @Override Control createViewControl(Composite parent, Client client) { Composite composite = new Composite(parent, SWT.NONE); Label heading = createHeading(composite, Messages.ClientEditorLabelClientMasterData); valueName = new Label(composite, SWT.NONE); valueISIN = new Label(composite, SWT.NONE); valueTickerSymbol = new Label(composite, SWT.NONE); // layout FormLayout layout = new FormLayout(); layout.marginLeft = 5; layout.marginRight = 5; composite.setLayout(layout); FormData data = new FormData(); data.top = new FormAttachment(0, 5); heading.setLayoutData(data); data = new FormData(); data.top = new FormAttachment(heading, 5); data.left = new FormAttachment(0); data.right = new FormAttachment(100); valueName.setLayoutData(data); below(valueName, valueISIN); below(valueISIN, valueTickerSymbol); return composite; } @Override void setInput(Security security) { if (security == null) { clearLabel(valueName, valueISIN, valueTickerSymbol); } else { valueName.setText(security.getName()); valueISIN.setText(nonNullString(security.getIsin())); valueTickerSymbol.setText(nonNullString(security.getTickerSymbol())); } } } private static class NoteFacet extends SecurityFacet { private Label valueNote; public NoteFacet(Font boldFont, Color color) { super(boldFont, color); } @Override Control createViewControl(Composite parent, Client client) { Composite composite = new Composite(parent, SWT.NONE); Label heading = createHeading(composite, Messages.ColumnNote); valueNote = new Label(composite, SWT.NONE); // layout FormLayout layout = new FormLayout(); layout.marginLeft = 5; layout.marginRight = 5; composite.setLayout(layout); FormData data = new FormData(); data.top = new FormAttachment(0, 5); heading.setLayoutData(data); data = new FormData(); data.top = new FormAttachment(heading, 5); data.left = new FormAttachment(0); data.right = new FormAttachment(100); valueNote.setLayoutData(data); return composite; } @Override void setInput(Security security) { if (security == null || security.getNote() == null) valueNote.setText(EMPTY_LABEL); else valueNote.setText(escape(security.getNote())); } } private static class LatestQuoteFacet extends SecurityFacet { private Label valueLatestPrices; private Label valueLatestTrade; private Label valueDaysHigh; private Label valueDaysLow; private Label valueVolume; private Label valuePreviousClose; public LatestQuoteFacet(Font boldFont, Color color) { super(boldFont, color); } @Override public Control createViewControl(Composite parent, Client client) { Composite composite = new Composite(parent, SWT.NONE); Label headingQuotes = createHeading(composite, Messages.ColumnLatestPrice); Label labelLatestPrice = new Label(composite, SWT.NONE); labelLatestPrice.setText(Messages.ColumnLatestPrice); valueLatestPrices = new Label(composite, SWT.RIGHT); Label labelLatestTrade = new Label(composite, SWT.NONE); labelLatestTrade.setText(Messages.ColumnLatestTrade); valueLatestTrade = new Label(composite, SWT.RIGHT); Label labelDaysHigh = new Label(composite, SWT.NONE); labelDaysHigh.setText(Messages.ColumnDaysHigh); valueDaysHigh = new Label(composite, SWT.RIGHT); Label labelDaysLow = new Label(composite, SWT.NONE); labelDaysLow.setText(Messages.ColumnDaysLow); valueDaysLow = new Label(composite, SWT.RIGHT); Label labelVolume = new Label(composite, SWT.NONE); labelVolume.setText(Messages.ColumnVolume); valueVolume = new Label(composite, SWT.RIGHT); Label labelPreviousClose = new Label(composite, SWT.NONE); labelPreviousClose.setText(Messages.ColumnPreviousClose); valuePreviousClose = new Label(composite, SWT.RIGHT); // layout FormLayout layout = new FormLayout(); layout.marginLeft = 5; layout.marginRight = 5; composite.setLayout(layout); FormData data = new FormData(); data.top = new FormAttachment(0, 5); headingQuotes.setLayoutData(data); data = new FormData(); data.top = new FormAttachment(valueLatestPrices, 0, SWT.CENTER); labelLatestPrice.setLayoutData(data); data = new FormData(); data.top = new FormAttachment(headingQuotes, 5); data.left = new FormAttachment(50, 5); data.right = new FormAttachment(100); data.width = dateWidth(composite); valueLatestPrices.setLayoutData(data); placeBelow(valueLatestPrices, labelLatestTrade, valueLatestTrade); placeBelow(valueLatestTrade, labelDaysHigh, valueDaysHigh); placeBelow(valueDaysHigh, labelDaysLow, valueDaysLow); placeBelow(valueDaysLow, labelVolume, valueVolume); placeBelow(valueVolume, labelPreviousClose, valuePreviousClose); return composite; } @Override public void setInput(Security security) { if (security == null || security.getLatest() == null) { clearLabel(valueLatestPrices, valueLatestTrade, valueDaysHigh, valueDaysLow, valueVolume, valuePreviousClose); } else { LatestSecurityPrice p = security.getLatest(); valueLatestPrices.setText(Values.Quote.format(p.getValue())); valueLatestTrade.setText(Values.Date.format(p.getTime())); long daysHigh = p.getHigh(); valueDaysHigh.setText(daysHigh == LatestSecurityPrice.NOT_AVAILABLE ? Messages.LabelNotAvailable : Values.Quote.format(daysHigh)); long daysLow = p.getLow(); valueDaysLow.setText(daysLow == LatestSecurityPrice.NOT_AVAILABLE ? Messages.LabelNotAvailable : Values.Quote.format(daysLow)); long volume = p.getVolume(); valueVolume.setText(volume == LatestSecurityPrice.NOT_AVAILABLE ? Messages.LabelNotAvailable : String.format("%,d", volume)); //$NON-NLS-1$ long prevClose = p.getPreviousClose(); valuePreviousClose.setText(prevClose == LatestSecurityPrice.NOT_AVAILABLE ? Messages.LabelNotAvailable : Values.Quote.format(prevClose)); } } } private static class TaxonomyFacet extends SecurityFacet { private Taxonomy taxonomy; private Label heading; private List<Label> labels = new ArrayList<Label>(); public TaxonomyFacet(Taxonomy taxonomy, Font boldFont, Color color) { super(boldFont, color); this.taxonomy = taxonomy; } @Override Control createViewControl(Composite parent, Client client) { Composite composite = new Composite(parent, SWT.NONE); FormLayout layout = new FormLayout(); layout.marginLeft = 5; layout.marginRight = 5; composite.setLayout(layout); heading = createHeading(composite, taxonomy.getName()); FormData data = new FormData(); data.top = new FormAttachment(0, 5); data.left = new FormAttachment(0); data.right = new FormAttachment(100); heading.setLayoutData(data); for (int ii = 0; ii < taxonomy.getHeigth() - 1; ii++) { Label label = new Label(composite, SWT.NONE); labels.add(label); if (ii == 0) { data = new FormData(); data.top = new FormAttachment(heading, 5); data.left = new FormAttachment(0); data.right = new FormAttachment(100); label.setLayoutData(data); } else { below(labels.get(ii - 1), label); } } return composite; } @Override void setInput(final Security security) { final int[] count = new int[1]; final int[] weight = new int[1]; final Classification[] classification = new Classification[1]; if (security != null) { taxonomy.foreach(new Visitor() { @Override public void visit(Classification thisClassification, Assignment assignment) { if (security.equals(assignment.getInvestmentVehicle())) { count[0]++; if (assignment.getWeight() > weight[0]) { weight[0] = assignment.getWeight(); classification[0] = thisClassification; } } } }); } if (count[0] > 1) heading.setText(taxonomy.getName() + ' ' + MessageFormat.format(Messages.LabelOneOfX, count[0])); else heading.setText(taxonomy.getName()); List<Classification> path = classification[0] != null ? classification[0].getPathToRoot() : new ArrayList<Classification>(); for (int ii = 0; ii < labels.size(); ii++) labels.get(ii).setText(path.size() > ii + 1 ? escape(path.get(ii + 1).getName()) : EMPTY_LABEL); } } private Composite container; private List<SecurityFacet> children = new ArrayList<SecurityFacet>(); public SecurityDetailsViewer(Composite parent, int style, Client client) { this(parent, style, client, false); } public SecurityDetailsViewer(Composite parent, int style, Client client, boolean showMasterData) { container = new Composite(parent, style); container.setBackground(Display.getDefault().getSystemColor(SWT.COLOR_WHITE)); container.setBackgroundMode(SWT.INHERIT_FORCE); // fonts LocalResourceManager resources = new LocalResourceManager(JFaceResources.getResources(), container); Font boldFont = resources.createFont(FontDescriptor.createFrom(container.getFont()).setStyle(SWT.BOLD)); Color color = resources.createColor(Colors.HEADINGS.swt()); // facets GridLayoutFactory.fillDefaults().numColumns(1).applyTo(container); if (showMasterData) children.add(new MasterDataFacet(boldFont, color)); children.add(new LatestQuoteFacet(boldFont, color)); for (Taxonomy taxonomy : client.getTaxonomies()) children.add(new TaxonomyFacet(taxonomy, boldFont, color)); children.add(new NoteFacet(boldFont, color)); for (SecurityFacet child : children) { try { Control control = child.createViewControl(container, client); GridDataFactory.fillDefaults().grab(true, false).applyTo(control); } catch (Exception e) { PortfolioPlugin.log(e); } } } public Control getControl() { return container; } public void setInput(Security security) { for (SecurityFacet child : children) child.setInput(security); } }