use of org.knime.core.ui.node.workflow.NodeContainerUI in project knime-core by knime.
the class VerticAlignmentCenter method doLayout.
/**
* @param wfm the manager holding the nodes to layout
* @param nodeParts the nodes to align
* @return a map with offsets for the nodes
*/
static Map<NodeContainerEditPart, Integer> doLayout(final WorkflowManagerUI wfm, final NodeContainerEditPart[] nodeParts) {
if (nodeParts.length == 0) {
return Collections.emptyMap();
}
NodeContainerEditPart[] nodes = nodeParts.clone();
// sorts by the y position
Arrays.sort(nodes, new Comparator<NodeContainerEditPart>() {
@Override
public int compare(final NodeContainerEditPart o1, final NodeContainerEditPart o2) {
NodeUIInformation ui1 = o1.getNodeContainer().getUIInformation();
NodeUIInformation ui2 = o2.getNodeContainer().getUIInformation();
if (ui1 == null || ui2 == null) {
return 0;
}
if (ui1.getBounds()[1] < ui2.getBounds()[1]) {
return -1;
} else {
return (ui1.getBounds()[1] > ui2.getBounds()[1]) ? 1 : 0;
}
}
});
// most left node is the anchor that doesn't change
HashMap<NodeContainerEditPart, Integer> offsets = new HashMap<NodeContainerEditPart, Integer>();
NodeUIInformation nui = nodes[0].getNodeContainer().getUIInformation();
if (nui == null) {
LOGGER.warn("Only nodes with location information can be aligned.");
return Collections.emptyMap();
}
int refX = nui.getBounds()[0];
for (int i = 1; /* idx 0 is anchor */
i < nodes.length; i++) {
NodeContainerUI nc = nodes[i].getNodeContainer();
NodeUIInformation ui = nc.getUIInformation();
if (ui.getBounds()[0] != refX) {
offsets.put(nodes[i], refX - ui.getBounds()[0]);
}
}
return offsets;
}
use of org.knime.core.ui.node.workflow.NodeContainerUI in project knime-core by knime.
the class LayoutManager method doLayout.
/**
* @param nodes the nodes that should be laid out. If null, all nodes of the
* workflow manager passed to the constructor are laid out.
*/
public void doLayout(final Collection<NodeContainerUI> nodes) {
int X_STRETCH = 100;
int Y_STRETCH = 120;
if (WorkflowEditor.getActiveEditorSnapToGrid()) {
if (WorkflowEditor.getActiveEditorGridX() >= 70) {
X_STRETCH = WorkflowEditor.getActiveEditorGridX();
} else {
X_STRETCH = WorkflowEditor.getActiveEditorGridXOffset(X_STRETCH);
}
Y_STRETCH = WorkflowEditor.getActiveEditorGridYOffset(Y_STRETCH);
}
// add all nodes that should be laid out to the graph
Collection<NodeContainerUI> allNodes = nodes;
if (allNodes == null || allNodes.size() <= 1) {
allNodes = m_wfm.getNodeContainers();
}
// keep the left upper corner of the node cluster.
// Nodes laid out are placed right and below
int minX = Integer.MAX_VALUE;
int minY = Integer.MAX_VALUE;
// add all nodes that are to be laid out
for (NodeContainerUI nc : allNodes) {
Node gNode = createGraphNodeForNC(nc);
m_workbenchToGraphNodes.put(nc, gNode);
NodeUIInformation ui = nc.getUIInformation();
minX = (ui.getBounds()[0] < minX) ? ui.getBounds()[0] : minX;
minY = (ui.getBounds()[1] < minY) ? ui.getBounds()[1] : minY;
if (WorkflowEditor.getActiveEditorSnapToGrid()) {
Point nextGridLocation = WorkflowEditor.getActiveEditorNextGridLocation(new Point(minX, minY));
minX = nextGridLocation.x;
minY = nextGridLocation.y;
}
}
// find all connections that connect from/to our nodes,
// keep a flag that states: isClusterInternal
HashMap<ConnectionContainerUI, Boolean> allConns = new HashMap<ConnectionContainerUI, Boolean>();
for (ConnectionContainerUI conn : m_wfm.getConnectionContainers()) {
Node src = null;
if (!conn.getSource().equals(m_wfm.getID())) {
// if it's not a meta node incoming connection
src = m_workbenchToGraphNodes.get(m_wfm.getNodeContainer(conn.getSource()));
}
Node dest = null;
if (!conn.getDest().equals(m_wfm.getID())) {
// if it is not a meta node outgoing connection
dest = m_workbenchToGraphNodes.get(m_wfm.getNodeContainer(conn.getDest()));
}
boolean isInternal = (src != null && dest != null);
// if at least one node is auto laid out we need the connection
if (src != null || dest != null) {
allConns.put(conn, isInternal);
}
}
// Add all connections (internal and leading in/out the cluster)
// to the graph
Edge gEdge;
for (ConnectionContainerUI conn : allConns.keySet()) {
Node srcGraphNode;
Node destGraphNode;
if (conn.getSource().equals(m_wfm.getID())) {
// it connects to a meta node input port:
int portIdx = conn.getSourcePort();
srcGraphNode = m_workbenchWFMInports.get(portIdx);
if (srcGraphNode == null) {
srcGraphNode = m_g.createNode("Incoming " + portIdx, 0, portIdx * Y_STRETCH);
m_workbenchWFMInports.put(portIdx, srcGraphNode);
}
} else {
NodeContainerUI s = m_wfm.getNodeContainer(conn.getSource());
srcGraphNode = m_workbenchToGraphNodes.get(s);
if (srcGraphNode == null) {
// then it connects to an "outside" node
srcGraphNode = m_workbenchIncomingNodes.get(s);
if (srcGraphNode == null) {
srcGraphNode = createGraphNodeForNC(s);
m_workbenchIncomingNodes.put(s, srcGraphNode);
}
}
// else it is a connection inside the layout cluster
}
if (conn.getDest().equals(m_wfm.getID())) {
// it connects to a meta node output port
int portIdx = conn.getDestPort();
destGraphNode = m_workbenchWFMOutports.get(portIdx);
if (destGraphNode == null) {
destGraphNode = m_g.createNode("Outgoing " + portIdx, 250, portIdx * Y_STRETCH);
m_workbenchWFMOutports.put(portIdx, destGraphNode);
}
} else {
NodeContainerUI d = m_wfm.getNodeContainer(conn.getDest());
destGraphNode = m_workbenchToGraphNodes.get(d);
if (destGraphNode == null) {
// then it connects to an "outside" node
destGraphNode = m_workbenchOutgoingNodes.get(d);
if (destGraphNode == null) {
destGraphNode = createGraphNodeForNC(d);
m_workbenchOutgoingNodes.put(d, destGraphNode);
}
}
// else it is a connection within the layout cluster
}
gEdge = m_g.createEdge(srcGraphNode, destGraphNode);
if (gEdge != null) {
m_workbenchToGraphEdges.put(conn, gEdge);
m_parallelConns.put(gEdge, new LinkedList<ConnectionContainerUI>(Collections.singletonList(conn)));
} else {
// a connection between these node already exists in the graph
Edge graphEdge = srcGraphNode.getEdge(destGraphNode);
assert graphEdge != null;
// add the connection to list of parallel connections.
m_parallelConns.get(graphEdge).add(conn);
}
}
// AFTER creating all nodes, mark the incoming/outgoing nodes as fixed
boolean anchorsExist = false;
Map<Node, Boolean> anchorNodes = m_g.createBoolNodeMap();
for (Node n : m_workbenchIncomingNodes.values()) {
anchorsExist = true;
anchorNodes.put(n, Boolean.TRUE);
}
for (Node n : m_workbenchOutgoingNodes.values()) {
anchorsExist = true;
anchorNodes.put(n, Boolean.TRUE);
}
for (Node n : m_workbenchWFMInports.values()) {
anchorsExist = true;
anchorNodes.put(n, Boolean.TRUE);
}
for (Node n : m_workbenchWFMOutports.values()) {
anchorsExist = true;
anchorNodes.put(n, Boolean.TRUE);
}
SimpleLayeredLayouter layouter = new SimpleLayeredLayouter(m_initPlacementSeed);
layouter.setBalanceBranchings(!WorkflowEditor.getActiveEditorSnapToGrid());
if (anchorsExist) {
layouter.doLayout(m_g, anchorNodes);
} else {
layouter.doLayout(m_g, null);
}
// preserver the old stuff for undoers
m_oldBendpoints = new HashMap<ConnectionID, ConnectionUIInformation>();
m_oldCoordinates = new HashMap<NodeID, NodeUIInformation>();
// transfer new coordinates back to nodes
// with fixed nodes (lots of) the new coordinates of the nodes may not
// start at 0.
double coordOffsetX = Integer.MAX_VALUE;
double coordOffsetY = Integer.MAX_VALUE;
for (NodeContainerUI nc : allNodes) {
Node gNode = m_workbenchToGraphNodes.get(nc);
coordOffsetX = Math.min(coordOffsetX, m_g.getX(gNode));
coordOffsetY = Math.min(coordOffsetY, m_g.getY(gNode));
}
for (NodeContainerUI nc : allNodes) {
NodeUIInformation uiInfo = nc.getUIInformation();
if (uiInfo != null) {
Node gNode = m_workbenchToGraphNodes.get(nc);
int[] b = uiInfo.getBounds();
int x = (int) Math.round((m_g.getX(gNode) - coordOffsetX) * X_STRETCH) + minX;
int y = (int) Math.round((m_g.getY(gNode) - coordOffsetY) * Y_STRETCH) + minY;
NodeUIInformation newCoord = NodeUIInformation.builder().setNodeLocation(x, y, b[2], b[3]).setHasAbsoluteCoordinates(uiInfo.hasAbsoluteCoordinates()).setSnapToGrid(WorkflowEditor.getActiveEditorSnapToGrid()).build();
LOGGER.debug("Node " + nc + " gets auto-layout coordinates " + newCoord);
// save old coordinates for undo
m_oldCoordinates.put(nc.getID(), uiInfo);
// triggers gui update
nc.setUIInformation(newCoord);
}
}
// delete old bendpoints - transfer new ones
for (ConnectionContainerUI conn : allConns.keySet()) {
// store old bendpoint for undo
ConnectionUIInformation ui = conn.getUIInfo();
if (ui != null) {
m_oldBendpoints.put(conn.getID(), ui);
} else {
m_oldBendpoints.put(conn.getID(), null);
}
ConnectionUIInformation.Builder newUIBuilder = ConnectionUIInformation.builder();
Edge e = m_workbenchToGraphEdges.get(conn);
if (e == null) {
// a parallel connection not represented by the edge
continue;
}
List<ConnectionContainerUI> conns = m_parallelConns.get(e);
assert conns.size() > 0;
// that is how we created it!
assert conns.get(0) == conn;
ArrayList<Point2D> newBends = m_g.bends(e);
if (newBends != null && !newBends.isEmpty()) {
// half the node icon size...
int extraX = 16;
int extraY = 24;
for (int i = 0; i < newBends.size(); i++) {
Point2D b = newBends.get(i);
newUIBuilder.addBendpoint((int) Math.round((b.getX() - coordOffsetX) * X_STRETCH) + extraX + minX, (int) Math.round((b.getY() - coordOffsetY) * Y_STRETCH) + extraY + minY, i);
}
}
ConnectionUIInformation newUI = newUIBuilder.build();
conn.setUIInfo(newUI);
// compute bendpoints for parallel connections (slightly offset)
for (int i = 1; i < conns.size(); i++) {
// idx 0 == conn!
ConnectionContainerUI parConn = conns.get(i);
// destination port determines offset
int yOffset = (parConn.getDestPort() - conn.getDestPort()) * 10;
ConnectionUIInformation parUI = ConnectionUIInformation.builder(newUI).translate(new int[] { 0, yOffset }).build();
parConn.setUIInfo(parUI);
}
}
}
use of org.knime.core.ui.node.workflow.NodeContainerUI in project knime-core by knime.
the class AutoLayoutAction method runOnNodes.
/**
* {@inheritDoc}
*/
@Override
public synchronized void runOnNodes(final NodeContainerEditPart[] parts) {
ScrollingGraphicalViewer provider = (ScrollingGraphicalViewer) getEditor().getEditorSite().getSelectionProvider();
if (provider == null) {
return;
}
ArrayList<NodeContainerUI> nodes = null;
if (parts != null && parts.length > 0) {
nodes = new ArrayList<NodeContainerUI>(parts.length);
for (NodeContainerEditPart p : parts) {
nodes.add(p.getNodeContainer());
}
}
AutoLayoutCommand alc = new AutoLayoutCommand(getManager(), nodes);
// enables undo
getCommandStack().execute(alc);
// update the actions
getEditor().updateActions();
// Give focus to the editor again. Otherwise the actions (selection)
// is not updated correctly.
getWorkbenchPart().getSite().getPage().activate(getWorkbenchPart());
}
use of org.knime.core.ui.node.workflow.NodeContainerUI in project knime-core by knime.
the class DynamicNodeDescriptionCreator method addDescription.
/**
* Adds the single line description for all nodes contained in the category
* (and all sub categories) to the StringBuilder. It will separate the lines
* by a HTML new line tag.
*
* @param cat the category to add the descriptions for.
* @param bld the buffer to add the one line strings to.
* @param idsDisplayed a set of IDs of categories and templates already
* displayed. Items appearing twice will be skipped.
*/
public void addDescription(final Category cat, final StringBuilder bld, final Set<String> idsDisplayed) {
bld.append("<dl>");
bld.append("<dt><h2>In <b>");
bld.append(htmlString(cat.getName()));
bld.append("</b>:</h2></dt> \n");
if (!cat.hasChildren()) {
bld.append("<dd> - contains no nodes - </dd>");
} else {
bld.append("<dd><dl>");
for (IRepositoryObject child : cat.getChildren()) {
if (child instanceof Category) {
Category childCat = (Category) child;
if (!idsDisplayed.contains(childCat.getID())) {
idsDisplayed.add(childCat.getID());
addDescription(childCat, bld, idsDisplayed);
}
} else if (child instanceof NodeTemplate) {
NodeTemplate templ = (NodeTemplate) child;
if (!idsDisplayed.contains(templ.getID())) {
idsDisplayed.add(templ.getID());
addDescription(templ, /* useSingleLine */
true, bld);
}
} else if (child instanceof MetaNodeTemplate) {
MetaNodeTemplate templ = (MetaNodeTemplate) child;
if (!idsDisplayed.contains(templ.getID())) {
idsDisplayed.add(templ.getID());
NodeContainerUI manager = ((MetaNodeTemplate) child).getManager();
addDescription(manager, /* useSingleLine */
true, bld);
}
} else {
bld.append(" - contains unknown object (internal err!) -");
}
}
bld.append("</dl></dd>");
}
bld.append("</dl>");
}
use of org.knime.core.ui.node.workflow.NodeContainerUI in project knime-core by knime.
the class DynamicNodeDescriptionCreator method addSubWorkflowDescription.
private void addSubWorkflowDescription(final NodeContainerUI nc, final boolean useSingleLine, final StringBuilder bld) {
WorkflowManagerUI wfm;
if (nc instanceof SubNodeContainerUI) {
wfm = ((SubNodeContainerUI) nc).getWorkflowManager();
} else {
wfm = (WorkflowManagerUI) nc;
}
if (!useSingleLine) {
bld.append(getHeader());
bld.append("<h1>");
bld.append(nc.getName());
bld.append("</h1>");
if (nc.getCustomDescription() != null) {
bld.append("<h2>Description:</h2>");
bld.append("<p>" + nc.getCustomDescription() + "</p>");
}
bld.append("<h2>Contained nodes: </h2>");
for (NodeContainerUI child : wfm.getNodeContainers()) {
addDescription(child, true, bld);
}
bld.append("</body></html>");
} else {
bld.append("<dt><b>");
bld.append(nc.getName() + " contained nodes:");
bld.append("</b></dt>");
bld.append("<dd>");
bld.append("<dl>");
for (NodeContainerUI child : wfm.getNodeContainers()) {
addDescription(child, true, bld);
}
bld.append("</dl>");
bld.append("</dd>");
}
}
Aggregations