/** Populate the stored JGraph 5 facade from the mxGraph data model. */ public void syncJGraphFacade() { if (facade == null || graph == null) { return; } mxIGraphModel model = graph.getModel(); if (vertices != null) { Set<Object> vertexKeys = vertices.keySet(); for (Object vertex : vertexKeys) { Object mxVertex = vertices.get(vertex); mxGeometry geo = model.getGeometry(mxVertex); facade.setLocation(vertex, geo.getX(), geo.getY()); } } if (edges != null) { Set<Object> edgeKeys = edges.keySet(); for (Object edge : edgeKeys) { Object mxEdge = edges.get(edge); List<mxPoint> points = model.getGeometry(mxEdge).getPoints(); if (points != null) { facade.setIntermediatePoints(edge, points); } } } }
/** * Does a depth first search starting at the specified cell. Makes sure the specified swimlane is * never left by the algorithm. */ protected TreeNode dfs(Object cell, Object parent, Set<Object> visited) { if (visited == null) { visited = new HashSet<Object>(); } TreeNode node = null; if (cell != null && !visited.contains(cell) && !isVertexIgnored(cell)) { visited.add(cell); node = createNode(cell); mxIGraphModel model = graph.getModel(); TreeNode prev = null; Object[] out = graph.getEdges(cell, parent, invert, !invert, false); for (int i = 0; i < out.length; i++) { Object edge = out[i]; if (!isEdgeIgnored(edge)) { // Resets the points on the traversed edge if (resetEdges) { setEdgePoints(edge, null); } // Checks if terminal in same swimlane Object target = graph.getView().getVisibleTerminal(edge, invert); TreeNode tmp = dfs(target, parent, visited); if (tmp != null && model.getGeometry(target) != null) { if (prev == null) { node.child = tmp; } else { prev.next = tmp; } prev = tmp; } } } } return node; }
/** * Function: check * * <p>Checks the multiplicity for the given arguments and returns the error for the given * connection or null if the multiplicity does not apply. * * <p>Parameters: * * <p>graph - Reference to the enclosing graph instance. edge - Cell that represents the edge to * validate. source - Cell that represents the source terminal. target - Cell that represents the * target terminal. sourceOut - Number of outgoing edges from the source terminal. targetIn - * Number of incoming edges for the target terminal. */ public String check( mxGraph graph, Object edge, Object source, Object target, int sourceOut, int targetIn) { mxIGraphModel model = graph.getModel(); Object sourceValue = model.getValue(source); Object targetValue = model.getValue(target); StringBuffer error = new StringBuffer(); if ((this.source && checkType(graph, sourceValue, type, attr, value)) || (!this.source && checkType(graph, targetValue, type, attr, value))) { if (!isUnlimited()) { int m = getMaxValue(); if (m == 0 || (this.source && sourceOut >= m) || (!this.source && targetIn >= m)) { error.append(countError + "\n"); } } if (validNeighbors != null) { boolean isValid = !validNeighborsAllowed; Iterator<String> it = validNeighbors.iterator(); while (it.hasNext()) { String tmp = it.next(); if (this.source && checkType(graph, targetValue, tmp)) { isValid = validNeighborsAllowed; break; } else if (!this.source && checkType(graph, sourceValue, tmp)) { isValid = validNeighborsAllowed; break; } } if (!isValid) { error.append(typeError + "\n"); } } } return (error.length() > 0) ? error.toString() : null; }
/** Checks the type of the given value. */ public boolean checkNeighbors(mxGraph graph, Object edge, Object source, Object target) { mxIGraphModel model = graph.getModel(); Object sourceValue = model.getValue(source); Object targetValue = model.getValue(target); boolean isValid = !validNeighborsAllowed; Iterator<String> it = validNeighbors.iterator(); while (it.hasNext()) { String tmp = it.next(); if (this.source && checkType(graph, targetValue, tmp)) { isValid = validNeighborsAllowed; break; } else if (!this.source && checkType(graph, sourceValue, tmp)) { isValid = validNeighborsAllowed; break; } } return isValid; }
public CellSelector(final mxGraphComponent gc, final boolean withScroll) { this.gc = gc; this.graph = gc.getGraph(); this.view = graph.getView(); this.model = graph.getModel(); this.withScroll = withScroll; mxIEventListener updateListener = new mxIEventListener() { @Override public void invoke(Object sender, mxEventObject evt) { // System.out.println("Updating marker because of event: "+evt.getName()+" change: // "+evt.getProperties()); Object changes = evt.getProperty("changes"); if (changes != null && changes instanceof List) { for (Object change : ((List) changes)) { if (change != null && change instanceof mxStyleChange) { Object cell = ((mxStyleChange) change).getCell(); mxCellState state = view.getState(cell, false); if (currentSelectedCells.containsKey(cell)) { mxCellMarker thisCellSelector = currentSelectedCells.get(cell); thisCellSelector.unmark(); thisCellSelector.process( state, thisCellSelector.getMarkerColor(null, state, selectSetAsValid), selectSetAsValid); thisCellSelector.mark(); } } } } for (Entry<mxCell, mxCellMarker> el : currentSelectedCells.entrySet()) { el.getValue().unmark(); el.getValue().mark(); } } }; view.addListener(mxEvent.SCALE_AND_TRANSLATE, updateListener); view.addListener(mxEvent.SCALE, updateListener); view.addListener(mxEvent.TRANSLATE, updateListener); model.addListener(mxEvent.CHANGE, updateListener); }
/** * Implements <mxGraphLayout.execute>. * * <p>If the parent has any connected edges, then it is used as the root of the tree. Else, * <mxGraph.findTreeRoots> will be used to find a suitable root node within the set of children of * the given parent. */ public void execute(Object parent, Object root) { mxIGraphModel model = graph.getModel(); if (root == null) { // Takes the parent as the root if it has outgoing edges if (graph.getEdges(parent, model.getParent(parent), invert, !invert, false).length > 0) { root = parent; } // Tries to find a suitable root in the parent's // children else { List<Object> roots = graph.findTreeRoots(parent, true, invert); if (roots != null && roots.size() > 0) { for (int i = 0; i < roots.size(); i++) { if (!isVertexIgnored(roots.get(i)) && graph.getEdges(roots.get(i), null, invert, !invert, false).length > 0) { root = roots.get(i); break; } } } } } if (root != null) { parent = model.getParent(root); model.beginUpdate(); try { TreeNode node = dfs(root, parent, null); if (node != null) { layout(node); double x0 = graph.getGridSize(); double y0 = x0; if (!moveTree || model.getParent(parent) == model.getRoot()) { mxGeometry g = model.getGeometry(root); if (g != null) { x0 = g.getX(); y0 = g.getY(); } } mxRectangle bounds = null; if (horizontal) { bounds = horizontalLayout(node, x0, y0, null); } else { bounds = verticalLayout(node, null, x0, y0, null); } if (bounds != null) { double dx = 0; double dy = 0; if (bounds.getX() < 0) { dx = Math.abs(x0 - bounds.getX()); } if (bounds.getY() < 0) { dy = Math.abs(y0 - bounds.getY()); } if (parent != null) { mxRectangle size = graph.getStartSize(parent); dx += size.getWidth(); dy += size.getHeight(); // Resize parent swimlane if (resizeParent && !graph.isCellCollapsed(parent)) { mxGeometry g = model.getGeometry(parent); if (g != null) { double width = bounds.getWidth() + size.getWidth() - bounds.getX() + 2 * x0; double height = bounds.getHeight() + size.getHeight() - bounds.getY() + 2 * y0; g = (mxGeometry) g.clone(); if (g.getWidth() > width) { dx += (g.getWidth() - width) / 2; } else { g.setWidth(width); } if (g.getHeight() > height) { if (horizontal) { dy += (g.getHeight() - height) / 2; } } else { g.setHeight(height); } model.setGeometry(parent, g); } } } moveNode(node, dx, dy); } } } finally { model.endUpdate(); } } }
/** * This method is called when the user has created manually an edge in the graph, by dragging a * link between two spot cells. It checks whether the matching edge in the model exists, and tune * what should be done accordingly. * * @param cell the mxCell of the edge that has been manually created. */ protected void addEdgeManually(mxCell cell) { if (cell.isEdge()) { final mxIGraphModel graphModel = graph.getModel(); cell.setValue("New"); model.beginUpdate(); graphModel.beginUpdate(); try { Spot source = graph.getSpotFor(cell.getSource()); Spot target = graph.getSpotFor(cell.getTarget()); if (DEBUG) { System.out.println( "[TrackScheme] #addEdgeManually: edge is between 2 spots belonging to the same frame. Removing it."); System.out.println( "[TrackScheme] #addEdgeManually: adding edge between source " + source + " at frame " + source.getFeature(Spot.FRAME).intValue() + " and target " + target + " at frame " + target.getFeature(Spot.FRAME).intValue()); } if (Spot.frameComparator.compare(source, target) == 0) { // Prevent adding edges between spots that belong to the same frame if (DEBUG) { System.out.println( "[TrackScheme] addEdgeManually: edge is between 2 spots belonging to the same frame. Removing it."); } graph.removeCells(new Object[] {cell}); } else { // We can add it to the model // Put them right in order: since we use a oriented graph, // we want the source spot to precede in time. if (Spot.frameComparator.compare(source, target) > 0) { if (DEBUG) { System.out.println( "[TrackScheme] #addEdgeManually: Source " + source + " succeed target " + target + ". Inverting edge direction."); } Spot tmp = source; source = target; target = tmp; } // We add a new jGraphT edge to the underlying model, if it does not exist yet. DefaultWeightedEdge edge = model.getTrackModel().getEdge(source, target); if (null == edge) { edge = model.addEdge(source, target, -1); if (DEBUG) { System.out.println( "[TrackScheme] #addEdgeManually: Creating new edge: " + edge + "."); } } else { // Ah. There was an existing edge in the model we were trying to re-add there, from the // graph. // We remove the graph edge we have added, if (DEBUG) { System.out.println("[TrackScheme] #addEdgeManually: Edge pre-existed. Retrieve it."); } graph.removeCells(new Object[] {cell}); // And re-create a graph edge from the model edge. cell = graph.addJGraphTEdge(edge); cell.setValue(String.format("%.1f", model.getTrackModel().getEdgeWeight(edge))); // We also need now to check if the edge belonged to a visible track. If not, // we make it visible. int ID = model.getTrackModel().trackIDOf(edge); // This will work, because track indices will be reprocessed only after the // graphModel.endUpdate() // reaches 0. So now, it's like we are dealing with the track indices priori to // modification. if (model.getTrackModel().isVisible(ID)) { if (DEBUG) { System.out.println( "[TrackScheme] #addEdgeManually: Track was visible. Do nothing."); } } else { if (DEBUG) { System.out.println( "[TrackScheme] #addEdgeManually: Track was invisible. Make it visible."); } importTrack(ID); } } graph.mapEdgeToCell(edge, cell); } } finally { graphModel.endUpdate(); model.endUpdate(); selectionModel.clearEdgeSelection(); } } }
/** Populate a fresh mxGraph data model from a JGraph data model */ public void syncMx(JGraph inputGraph) { if (inputGraph != null) { jgraph = inputGraph; } else { return; } GraphModel jModel = jgraph.getModel(); mxIGraphModel mxModel = null; if (graph == null) { mxModel = new mxGraphModel(); this.graph = new mxGraph(mxModel); } mxModel = graph.getModel(); mxModel.beginUpdate(); try { int rootCount = jModel.getRootCount(); // Insert everything in mx in the same order and // hierarchy as jgraph for (int i = 0; i < rootCount; i++) { Object cell = jModel.getRootAt(i); if (cell != null) { insertCell(cell, graph.getDefaultParent()); } } // Edges are inserted without source and targets, // since the vertices may not exist at insertion // time if (edges != null && vertices != null) { Set<Object> keys = edges.keySet(); for (Object edge : keys) { Object source = jModel.getSource(edge); Object target = jModel.getTarget(edge); Object mxEdge = edges.get(edge); if (facade != null) { source = facade.getSource(edge); target = facade.getTarget(edge); } if (source != null) { source = vertices.get(source); graph.connectCell(mxEdge, source, true); } if (target != null) { target = vertices.get(target); graph.connectCell(mxEdge, target, false); } } } } catch (Exception e) { e.printStackTrace(); } finally { mxModel.endUpdate(); } }