/** * Copyright (C) 2009 - present by OpenGamma Inc. and the OpenGamma group of companies * * Please see distribution for license. */ package com.opengamma.integration.viewer; import java.util.ArrayList; import java.util.Map; import javax.swing.event.TreeModelEvent; import javax.swing.event.TreeModelListener; import javax.swing.tree.TreePath; import org.jdesktop.swingx.treetable.AbstractTreeTableModel; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.threeten.bp.Instant; import com.opengamma.OpenGammaRuntimeException; import com.opengamma.core.LinkUtils; import com.opengamma.core.position.PortfolioNode; import com.opengamma.core.position.Position; import com.opengamma.engine.ComputationTargetSpecification; import com.opengamma.engine.value.ComputedValueResult; import com.opengamma.engine.value.ValueProperties; import com.opengamma.engine.view.ViewCalculationResultModel; import com.opengamma.engine.view.ViewComputationResultModel; import com.opengamma.engine.view.ViewDeltaResultModel; import com.opengamma.engine.view.compilation.CompiledViewDefinition; import com.opengamma.engine.view.cycle.ViewCycleMetadata; import com.opengamma.engine.view.execution.ViewCycleExecutionOptions; import com.opengamma.engine.view.listener.ViewResultListener; import com.opengamma.id.UniqueIdentifiable; import com.opengamma.livedata.UserPrincipal; import com.opengamma.util.tuple.Pair; class PortfolioTreeTableModel extends AbstractTreeTableModel implements ViewResultListener { private static final Logger s_logger = LoggerFactory.getLogger(PortfolioTreeTableModel.class); private static final String UNAVAILABLE_VALUE = "N/A"; private ViewerColumnModel _columnModel; private PortfolioNode _treeRoot; private ViewComputationResultModel _resultModel; public PortfolioTreeTableModel() { _columnModel = new ViewerColumnModel(); } @Override public Object getRoot() { return _treeRoot; } @Override public synchronized String getColumnName(int column) { if (column == 0) { return "Trade"; } else { return _columnModel.getCalculationConfigurationName(column) + "-" + _columnModel.getRequirementName(column); } } @Override public synchronized int getColumnCount() { return _columnModel.getColumnCount(); } /* private void dumpPortfolio(PortfolioNode node, int depth) { StringBuilder indent = new StringBuilder(); for (int i=0; i<depth; i++) indent.append(" "); s_logger.info("{}{}", indent.toString(), node); if (node.getPositions() != null) { for (Position position : node.getPositions()) { s_logger.info("{} {}", indent.toString(), position); } } if (node.getSubNodes() != null) { for (PortfolioNode subNode : node.getSubNodes()) { dumpPortfolio(subNode, depth+2); } } } */ //------------------------------------------------------------------------- @Override public UserPrincipal getUser() { return UserPrincipal.getLocalUser(); } @Override public void viewDefinitionCompiled(CompiledViewDefinition compiledViewDefinition, boolean hasMarketDataPermissions) { _columnModel.init(compiledViewDefinition.getViewDefinition()); _treeRoot = compiledViewDefinition.getPortfolio().getRootNode(); fireTreeStructureChanged(); } @Override public void viewDefinitionCompilationFailed(Instant valuationTime, Exception exception) { } @Override public void cycleStarted(ViewCycleMetadata cycleMetadata) { //ignore } @Override public void cycleFragmentCompleted(ViewComputationResultModel fullFragment, ViewDeltaResultModel deltaFragment) { //ignore } @Override public void cycleCompleted(ViewComputationResultModel fullResult, ViewDeltaResultModel deltaResult) { _resultModel = fullResult; fireTreeNodesChanged(); } @Override public void cycleExecutionFailed(ViewCycleExecutionOptions executionOptions, Exception exception) { } @Override public void processCompleted() { } @Override public void processTerminated(boolean executionInterrupted) { } @Override public void clientShutdown(Exception e) { } //------------------------------------------------------------------------- private void fireTreeNodesChanged() { TreeModelEvent treeModelEvent = new TreeModelEvent(this, new TreePath(getRoot()), null, null); for (TreeModelListener listener : getTreeModelListeners()) { listener.treeNodesChanged(treeModelEvent); } } private void fireTreeStructureChanged() { TreeModelEvent treeModelEvent = new TreeModelEvent(this, new TreePath(getRoot()), null, null); for (TreeModelListener listener : getTreeModelListeners()) { listener.treeStructureChanged(treeModelEvent); } } private Object renderForColumn(ComputationTargetSpecification targetSpec, int column) { String calcConfigName = _columnModel.getCalculationConfigurationName(column); String requirementName = _columnModel.getRequirementName(column); if (_resultModel == null || calcConfigName == null || requirementName == null) { s_logger.warn("Unhandled column {}", column); return UNAVAILABLE_VALUE; } ViewCalculationResultModel calcResultModel = _resultModel.getCalculationResult(calcConfigName); Map<Pair<String, ValueProperties>, ComputedValueResult> values = calcResultModel.getValues(targetSpec); if (values == null) { s_logger.debug("No values available for {}", targetSpec); return UNAVAILABLE_VALUE; } // TODO 2011-06-15 -- support value name AND value properties so that the required value can be looked up directly for (Map.Entry<Pair<String, ValueProperties>, ComputedValueResult> valueEntry : values.entrySet()) { if (valueEntry.getKey().getFirst().equals(requirementName)) { return valueEntry.getValue().toString(); } } return UNAVAILABLE_VALUE; } protected String getNodeTitle(Object node) { if (node instanceof Position) { Position position = (Position) node; String key = LinkUtils.bestName(position.getSecurityLink()); return key + " @ " + position.getQuantity(); } else if (node instanceof PortfolioNode) { return ((PortfolioNode) node).getName(); } else { return "Unknown Node"; } } @Override public synchronized Object getValueAt(Object node, int column) { //s_logger.info("getValueAt({}, {})", node, column); if (node == null) { return null; } if (column == 0) { return getNodeTitle(node); } if (node instanceof UniqueIdentifiable) { ComputationTargetSpecification targetSpec = ComputationTargetSpecification.of(((UniqueIdentifiable) node).getUniqueId()); return renderForColumn(targetSpec, column); } return "Unknown object: " + node; } @Override public synchronized Object getChild(Object parent, int index) { //s_logger.info("getChild({}, {})", parent, index); if (parent == null) { return null; } if (parent instanceof Position) { throw new OpenGammaRuntimeException("Unexpected call to getChild on a position"); } else if (parent instanceof PortfolioNode) { PortfolioNode node = (PortfolioNode) parent; if (index < node.getPositions().size()) { return (node.getPositions().toArray())[index]; } else { return (node.getChildNodes().toArray())[index - node.getPositions().size()]; } } else { throw new OpenGammaRuntimeException("Unexpected call to getChild on a unexpected type " + parent); } } @Override public synchronized int getChildCount(Object parent) { //s_logger.info("getChildCount({})", parent); if (parent == null) { return 0; } if (parent instanceof Position) { return 0; } else if (parent instanceof PortfolioNode) { PortfolioNode node = (PortfolioNode) parent; return node.size(); } else { throw new OpenGammaRuntimeException("Unexpected call to getChild on a unexpected type " + parent); } } @Override public synchronized int getIndexOfChild(Object parent, Object child) { //s_logger.info("getIndexOfChild({}, {})", parent, child); if (parent == null) { return 0; } if (parent instanceof Position) { return 0; } else if (parent instanceof PortfolioNode) { PortfolioNode node = (PortfolioNode) parent; if (child instanceof Position) { return new ArrayList<Position>(node.getPositions()).indexOf(child); } else { return new ArrayList<PortfolioNode>(node.getChildNodes()).indexOf(child) + node.getPositions().size(); } } else { throw new OpenGammaRuntimeException("Unexpected call to getChild on a unexpected type " + parent); } } public synchronized boolean isLeaf(Object node) { if (node == null) { return true; } if (node instanceof Position) { return true; } if (node instanceof PortfolioNode) { return ((PortfolioNode) node).size() == 0; } return false; } }