| /******************************************************************************* |
| * Copyright (C) 2007 The University of Manchester |
| * |
| * Modifications to the initial code base are copyright of their |
| * respective authors, or their employers as appropriate. |
| * |
| * This program is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU Lesser General Public License |
| * as published by the Free Software Foundation; either version 2.1 of |
| * the License, or (at your option) any later version. |
| * |
| * This program is distributed in the hope that it will be useful, but |
| * WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| * Lesser General Public License for more details. |
| * |
| * You should have received a copy of the GNU Lesser General Public |
| * License along with this program; if not, write to the Free Software |
| * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 |
| ******************************************************************************/ |
| package net.sf.taverna.t2.workbench.views.results.workflow; |
| |
| import static javax.swing.SwingUtilities.invokeLater; |
| import static net.sf.taverna.t2.workbench.views.results.workflow.WorkflowResultTreeNode.ResultTreeNodeState.RESULT_LIST; |
| import static net.sf.taverna.t2.workbench.views.results.workflow.WorkflowResultTreeNode.ResultTreeNodeState.RESULT_REFERENCE; |
| import static net.sf.taverna.t2.workbench.views.results.workflow.WorkflowResultTreeNode.ResultTreeNodeState.RESULT_WAITING; |
| |
| import java.io.IOException; |
| import java.nio.file.Path; |
| import java.util.List; |
| |
| import javax.swing.tree.DefaultTreeModel; |
| |
| import net.sf.taverna.t2.workbench.views.results.workflow.WorkflowResultTreeNode.ResultTreeNodeState; |
| |
| import org.apache.log4j.Logger; |
| |
| import uk.org.taverna.databundle.DataBundles; |
| import uk.org.taverna.platform.report.ReportListener; |
| import uk.org.taverna.platform.report.State; |
| |
| public class WorkflowResultTreeModel extends DefaultTreeModel implements ReportListener { |
| private static final long serialVersionUID = 7154527821423588046L; |
| private static final Logger logger = Logger.getLogger(WorkflowResultTreeModel.class); |
| |
| /** Name of the output port this class models results for */ |
| private String portName; |
| int depthSeen = -1; |
| |
| public WorkflowResultTreeModel(String portName) { |
| super(new WorkflowResultTreeNode(ResultTreeNodeState.RESULT_TOP)); |
| this.portName = portName; |
| } |
| |
| @Override |
| public void outputAdded(final Path path, final String portName, final int[] index) { |
| // Don't slow down workflow execution, do it in GUI thread |
| invokeLater(new Runnable() { |
| @Override |
| public void run() { |
| resultTokenProducedGui(path, portName, index); |
| } |
| }); |
| } |
| |
| @Override |
| public void stateChanged(State oldState, State newState) { |
| // TODO Auto-generated method stub |
| } |
| |
| public void resultTokenProducedGui(Path path, String portName, int[] index) { |
| if (!this.portName.equals(portName)) |
| return; |
| if (depthSeen == -1) |
| depthSeen = index.length; |
| else if (index.length < depthSeen) |
| return; |
| |
| Path reference = path; |
| if (!DataBundles.isList(reference)) { |
| insertNewDataTokenNode(reference, index); |
| return; |
| } |
| |
| try { |
| WorkflowResultTreeNode parent = (WorkflowResultTreeNode) getRoot(); |
| parent = getChildAt(parent,0); |
| changeState(parent, RESULT_LIST); |
| for (int i = 0; i < index.length; i++) { |
| parent = getChildAt(parent, index[i]); |
| changeState(parent, RESULT_LIST); |
| } |
| |
| List<Path> list = DataBundles.getList(reference); |
| int[] elementIndex = new int[index.length + 1]; |
| for (int indexElement = 0; indexElement < index.length; indexElement++) |
| elementIndex[indexElement] = index[indexElement]; |
| int c = 0; |
| for (Path id : list) { |
| elementIndex[index.length] = c; |
| resultTokenProducedGui(id, portName, elementIndex); |
| c++; |
| } |
| //if (c == 0) { |
| // parent.setUserObject("Empty list (depth=" + reference.getDepth() + ")" + reference.getLocalPart()); |
| // nodeChanged(parent); |
| //} |
| } catch (NullPointerException | IOException e) { |
| logger.error("Error resolving data entity list " + reference, e); |
| } |
| } |
| |
| public void insertNewDataTokenNode(Path reference, int[] index) { |
| WorkflowResultTreeNode parent = (WorkflowResultTreeNode) getRoot(); |
| if (DataBundles.isError(reference)) { |
| parent = getChildAt(parent, 0); |
| for (int i = 0; i < index.length - 1; i++) { |
| parent = getChildAt(parent, index[i]); |
| parent = getChildAt(parent, 0); |
| changeState(parent, RESULT_LIST); |
| } |
| if (index.length > 0) { |
| WorkflowResultTreeNode child = getChildAt(parent, |
| index[index.length - 1]); |
| updateNodeWithData(child, reference); |
| } else |
| updateNodeWithData(parent, reference); |
| } else { |
| int depth = index.length; |
| if (depth == 0) { |
| WorkflowResultTreeNode child = getChildAt(parent, 0); |
| updateNodeWithData(child, reference); |
| } else { |
| parent = getChildAt(parent, 0); |
| changeState(parent, RESULT_LIST); |
| for (int indexElement = 0; indexElement < depth; indexElement++) { |
| WorkflowResultTreeNode child = getChildAt(parent, |
| index[indexElement]); |
| if (indexElement == depth - 1) // leaf |
| updateNodeWithData(child, reference); |
| else { // list |
| child.setState(RESULT_LIST); |
| nodeChanged(child); |
| } |
| parent = child; |
| } |
| } |
| } |
| } |
| |
| private void updateNodeWithData(WorkflowResultTreeNode node, Path reference) { |
| node.setState(RESULT_REFERENCE); |
| node.setReference(reference); |
| nodeChanged(node); |
| } |
| |
| private WorkflowResultTreeNode getChildAt(WorkflowResultTreeNode parent, |
| int i) { |
| int childCount = getChildCount(parent); |
| if (childCount <= i) |
| for (int x = childCount; x <= i; x++) |
| insertNodeInto(new WorkflowResultTreeNode(RESULT_WAITING), |
| parent, x); |
| return (WorkflowResultTreeNode) parent.getChildAt(i); |
| } |
| |
| private void changeState(WorkflowResultTreeNode node, ResultTreeNodeState state) { |
| if (!node.isState(state)) { |
| node.setState(state); |
| nodeChanged(node); |
| } |
| } |
| |
| // Normally used for past workflow runs where data is obtained from provenance |
| public void createTree(Path path, WorkflowResultTreeNode parentNode){ |
| // If reference contains a list of data references |
| if (DataBundles.isList(path)) |
| // insert list node |
| try { |
| List<Path> list = DataBundles.getList(path); |
| WorkflowResultTreeNode listNode = new WorkflowResultTreeNode( |
| path, RESULT_LIST); |
| insertNodeInto(listNode, parentNode, parentNode.getChildCount()); |
| for (Path ref : list) |
| createTree(ref, listNode); |
| } catch (IOException e) { |
| logger.error("Error resolving data entity list " + path, e); |
| } |
| else { // reference to single data or an error |
| // insert data node |
| WorkflowResultTreeNode dataNode = new WorkflowResultTreeNode(path, |
| RESULT_REFERENCE); |
| insertNodeInto(dataNode, parentNode, parentNode.getChildCount()); |
| } |
| } |
| |
| } |