Search in sources :

Example 1 with ExpandSubnodeResult

use of org.knime.core.node.workflow.action.ExpandSubnodeResult in project knime-core by knime.

the class Bug6029_ExpandSubnode method testExecuteAfterExpandAndCollapse.

@Test
public void testExecuteAfterExpandAndCollapse() throws Exception {
    WorkflowManager mgr = getManager();
    ExpandSubnodeResult expandSubWorkflowResult = mgr.expandSubWorkflow(m_subnode8);
    assertThat("Expected to be dirty after expand", mgr.isDirty(), is(true));
    assertThat("Subnode must not longer exist", mgr.getNodeContainer(m_subnode8, SubNodeContainer.class, false), is(nullValue()));
    ConnectionContainer flowVarConn = findInConnection(m_javaSnippet_After_Expand_3, 0);
    assertNotNull("didn't find connection after expand", flowVarConn);
    assertThat("Source should be string input node", flowVarConn.getSource(), is(m_stringInput5));
    executeAllAndWait();
    checkState(mgr, InternalNodeContainerState.EXECUTED);
    checkStateOfMany(InternalNodeContainerState.EXECUTED, m_tableDiffer7, m_javaSnippet_After_Expand_3);
    assertThat("Should be expandable but is not", expandSubWorkflowResult.canUndo(), is(Boolean.TRUE));
    expandSubWorkflowResult.undo();
    checkState(mgr, InternalNodeContainerState.CONFIGURED);
    assertThat("Subnode must have been re-created", mgr.getNodeContainer(m_subnode8, SubNodeContainer.class, false), is(not(nullValue())));
    assertThat("Java Snippet must have been removed/collapsed", mgr.getNodeContainer(m_javaSnippet_After_Expand_3, NativeNodeContainer.class, false), is(nullValue()));
    executeAllAndWait();
    checkState(mgr, InternalNodeContainerState.EXECUTED);
    checkStateOfMany(InternalNodeContainerState.EXECUTED, m_tableDiffer7, m_subnode8);
}
Also used : ExpandSubnodeResult(org.knime.core.node.workflow.action.ExpandSubnodeResult) Test(org.junit.Test)

Example 2 with ExpandSubnodeResult

use of org.knime.core.node.workflow.action.ExpandSubnodeResult in project knime-core by knime.

the class WorkflowManager method expandSubWorkflow.

/**
 * Expand the selected subnode into a set of nodes in this WFM and remove the old metanode.
 *
 * @param nodeID ID of the node containing the sub workflow
 * @return copied content containing nodes and annotations
 * @throws IllegalStateException if expand cannot be done
 * @since 2.12
 * @noreference This method is not intended to be referenced by clients.
 */
public ExpandSubnodeResult expandSubWorkflow(final NodeID nodeID) throws IllegalStateException {
    try (WorkflowLock lock = lock()) {
        WorkflowCopyContent.Builder cnt = WorkflowCopyContent.builder();
        cnt.setNodeIDs(nodeID);
        cnt.setIncludeInOutConnections(true);
        WorkflowPersistor undoCopyPersistor = copy(true, cnt.build());
        final NodeContainer node = getNodeContainer(nodeID);
        final WorkflowManager subWFM;
        HashSet<NodeID> virtualNodes = new HashSet<NodeID>();
        if (node instanceof WorkflowManager) {
            CheckUtils.checkState(canExpandMetaNode(nodeID) == null, canExpandMetaNode(nodeID));
            subWFM = (WorkflowManager) node;
        } else if (node instanceof SubNodeContainer) {
            CheckUtils.checkState(canExpandSubNode(nodeID) == null, canExpandSubNode(nodeID));
            SubNodeContainer snc = (SubNodeContainer) node;
            virtualNodes.add(snc.getVirtualInNodeID());
            virtualNodes.add(snc.getVirtualOutNodeID());
            subWFM = snc.getWorkflowManager();
        } else {
            throw new IllegalStateException("Not a sub- or metanode: " + node);
        }
        // retrieve all nodes from metanode
        Collection<NodeContainer> ncs = subWFM.getNodeContainers();
        NodeID[] orgIDs = new NodeID[ncs.size()];
        int i = 0;
        for (NodeContainer nc : ncs) {
            orgIDs[i] = nc.getID();
            i++;
        }
        // retrieve all workflow annotations
        Collection<WorkflowAnnotation> annos = subWFM.getWorkflowAnnotations();
        WorkflowAnnotation[] orgAnnos = annos.toArray(new WorkflowAnnotation[annos.size()]);
        // copy the nodes from the sub workflow manager:
        WorkflowCopyContent.Builder orgContent = WorkflowCopyContent.builder();
        orgContent.setNodeIDs(orgIDs);
        orgContent.setAnnotation(orgAnnos);
        WorkflowCopyContent newContent = this.copyFromAndPasteHere(subWFM, orgContent.build());
        NodeID[] newIDs = newContent.getNodeIDs();
        Annotation[] newAnnos = newContent.getAnnotations();
        // create map and set of quick lookup/search
        Map<NodeID, NodeID> oldIDsHash = new HashMap<NodeID, NodeID>();
        HashSet<NodeID> newIDsHashSet = new HashSet<NodeID>();
        for (i = 0; i < orgIDs.length; i++) {
            oldIDsHash.put(orgIDs[i], newIDs[i]);
            newIDsHashSet.add(newIDs[i]);
        }
        if (node instanceof WorkflowManager) {
            // connect connections TO the sub workflow:
            for (ConnectionContainer cc : m_workflow.getConnectionsByDest(subWFM.getID())) {
                int destPortIndex = cc.getDestPort();
                for (ConnectionContainer subCC : subWFM.m_workflow.getConnectionsBySource(subWFM.getID())) {
                    if (subCC.getSourcePort() == destPortIndex) {
                        if (subCC.getDest().equals(subWFM.getID())) {
                        // THROUGH connection - skip here, handled below!
                        } else {
                            // reconnect
                            NodeID newID = oldIDsHash.get(subCC.getDest());
                            this.addConnection(cc.getSource(), cc.getSourcePort(), newID, subCC.getDestPort());
                        }
                    }
                }
            }
            // connect connection FROM the sub workflow
            for (ConnectionContainer cc : getOutgoingConnectionsFor(subWFM.getID())) {
                int sourcePortIndex = cc.getSourcePort();
                ConnectionContainer subCC = subWFM.getIncomingConnectionFor(subWFM.getID(), sourcePortIndex);
                if (subCC != null) {
                    if (subCC.getSource().equals(subWFM.getID())) {
                        // THROUGH connection
                        ConnectionContainer incomingCC = this.getIncomingConnectionFor(subWFM.getID(), subCC.getSourcePort());
                        // delete existing connection from Metanode to
                        // Node (done automatically) and reconnect
                        this.addConnection(incomingCC.getSource(), incomingCC.getSourcePort(), cc.getDest(), cc.getDestPort());
                    } else {
                        // delete existing connection from Metanode to Node (automatically) and reconnect
                        NodeID newID = oldIDsHash.get(subCC.getSource());
                        this.addConnection(newID, subCC.getSourcePort(), cc.getDest(), cc.getDestPort());
                    }
                }
            }
        } else if (node instanceof SubNodeContainer) {
            // connect connections TO the sub workflow:
            for (ConnectionContainer outerConnection : m_workflow.getConnectionsByDest(nodeID)) {
                for (ConnectionContainer innerConnection : subWFM.m_workflow.getConnectionsBySource(((SubNodeContainer) node).getVirtualInNodeID())) {
                    if (outerConnection.getDestPort() == innerConnection.getSourcePort()) {
                        addConnection(outerConnection.getSource(), outerConnection.getSourcePort(), oldIDsHash.get(innerConnection.getDest()), innerConnection.getDestPort());
                    }
                }
            }
            // connect connections FROM the sub workflow:
            List<ConnectionContainer> cons = new ArrayList<ConnectionContainer>();
            cons.addAll(m_workflow.getConnectionsBySource(nodeID));
            for (ConnectionContainer outerConnection : cons) {
                for (ConnectionContainer innerConnection : subWFM.m_workflow.getConnectionsByDest(((SubNodeContainer) node).getVirtualOutNodeID())) {
                    if (outerConnection.getSourcePort() == innerConnection.getDestPort()) {
                        addConnection(oldIDsHash.get(innerConnection.getSource()), innerConnection.getSourcePort(), outerConnection.getDest(), outerConnection.getDestPort());
                    }
                }
            }
        }
        // move nodes so that their center lies on the position of
        // the old metanode!
        // ATTENTION: if you change this make sure it is (correctly)
        // revertable by collapseToMetaNodes (undo-redo!)
        int xmin = Integer.MAX_VALUE;
        int ymin = Integer.MAX_VALUE;
        int xmax = Integer.MIN_VALUE;
        int ymax = Integer.MIN_VALUE;
        for (i = 0; i < newIDs.length; i++) {
            NodeContainer nc = getNodeContainer(newIDs[i]);
            NodeUIInformation uii = nc.getUIInformation();
            if (uii != null) {
                int[] bounds = uii.getBounds();
                if (bounds.length >= 2) {
                    xmin = Math.min(bounds[0], xmin);
                    ymin = Math.min(bounds[1], ymin);
                    xmax = Math.max(bounds[0], xmax);
                    ymax = Math.max(bounds[1], ymax);
                }
            }
        }
        NodeUIInformation uii = node.getUIInformation();
        if (uii != null) {
            int[] metaBounds = uii.getBounds();
            int xShift = metaBounds[0] - (xmin + xmax) / 2;
            int yShift = metaBounds[1] - (ymin + ymax) / 2;
            for (i = 0; i < newIDs.length; i++) {
                NodeContainer nc = getNodeContainer(newIDs[i]);
                uii = nc.getUIInformation();
                if (uii != null) {
                    NodeUIInformation newUii = NodeUIInformation.builder(uii).translate(new int[] { xShift, yShift }).build();
                    nc.setUIInformation(newUii);
                }
            }
            for (Annotation anno : newAnnos) {
                anno.shiftPosition(xShift, yShift);
            }
            // move bendpoints of connections between moved nodes
            for (ConnectionContainer cc : this.getConnectionContainers()) {
                if ((newIDsHashSet.contains(cc.getSource())) && (newIDsHashSet.contains(cc.getDest()))) {
                    ConnectionUIInformation cuii = cc.getUIInfo();
                    if (cuii != null) {
                        ConnectionUIInformation newUI = ConnectionUIInformation.builder(cuii).translate(new int[] { xShift, yShift }).build();
                        cc.setUIInfo(newUI);
                    }
                }
            }
        }
        // remove virtual nodes
        for (NodeID id : virtualNodes) {
            removeNode(oldIDsHash.get(id));
        }
        // and finally remove old sub workflow
        this.removeNode(nodeID);
        return new ExpandSubnodeResult(this, newContent, undoCopyPersistor);
    }
}
Also used : LinkedHashMap(java.util.LinkedHashMap) HashMap(java.util.HashMap) CopyOnWriteArrayList(java.util.concurrent.CopyOnWriteArrayList) ArrayList(java.util.ArrayList) List(java.util.List) LinkedList(java.util.LinkedList) ExpandSubnodeResult(org.knime.core.node.workflow.action.ExpandSubnodeResult) LinkedHashSet(java.util.LinkedHashSet) HashSet(java.util.HashSet) IExtensionPoint(org.eclipse.core.runtime.IExtensionPoint)

Aggregations

ExpandSubnodeResult (org.knime.core.node.workflow.action.ExpandSubnodeResult)2 ArrayList (java.util.ArrayList)1 HashMap (java.util.HashMap)1 HashSet (java.util.HashSet)1 LinkedHashMap (java.util.LinkedHashMap)1 LinkedHashSet (java.util.LinkedHashSet)1 LinkedList (java.util.LinkedList)1 List (java.util.List)1 CopyOnWriteArrayList (java.util.concurrent.CopyOnWriteArrayList)1 IExtensionPoint (org.eclipse.core.runtime.IExtensionPoint)1 Test (org.junit.Test)1