📄 jawegraphmodel.java
字号:
package org.enhydra.jawe.components.graph;import java.io.IOException;import java.io.ObjectInputStream;import java.io.Serializable;import java.util.ArrayList;import java.util.HashSet;import java.util.Hashtable;import java.util.Iterator;import java.util.LinkedList;import java.util.List;import java.util.Map;import java.util.Set;import java.util.Stack;import javax.swing.event.EventListenerList;import javax.swing.tree.DefaultMutableTreeNode;import javax.swing.tree.MutableTreeNode;import javax.swing.tree.TreeNode;import javax.swing.undo.AbstractUndoableEdit;import javax.swing.undo.CannotRedoException;import javax.swing.undo.CannotUndoException;import javax.swing.undo.CompoundEdit;import javax.swing.undo.UndoableEdit;import javax.swing.undo.UndoableEditSupport;import org.enhydra.jawe.ResourceManager;import org.jgraph.event.GraphModelEvent;import org.jgraph.event.GraphModelListener;import org.jgraph.graph.AttributeMap;import org.jgraph.graph.CellView;import org.jgraph.graph.ConnectionSet;import org.jgraph.graph.DefaultGraphCell;import org.jgraph.graph.DefaultGraphModel;import org.jgraph.graph.Edge;import org.jgraph.graph.GraphCell;import org.jgraph.graph.GraphConstants;import org.jgraph.graph.GraphLayoutCache;import org.jgraph.graph.GraphModel;import org.jgraph.graph.ParentMap;import org.jgraph.graph.Port;/** * A process editor implementation of a graph model. * @author Sasa Bojanic */public class JaWEGraphModel extends UndoableEditSupport implements Serializable, GraphModel { /** The list of listeners that listen to the model. */ protected transient EventListenerList listenerList = new EventListenerList(); /** Default instance of an empty iterator. */ protected transient Iterator emptyIterator = new EmptyIterator(); /** Set that contains all root cells of this model. */ protected List roots = new ArrayList(); /** Indicates whether isLeaf is based on a node's allowsChildren value. */ protected boolean asksAllowsChildren = false; /** * Constructs a model that is not an attribute store. */ public JaWEGraphModel() { } // // Graph Model // /** * Returns the number of roots in the model. Returns 0 if the * model is empty. * * @return the number of roots in the model */ public int getRootCount() { return roots.size(); } /** * Returns the root at index <I>index</I> in the model. * This should not return null if <i>index</i> is a valid * index for the model (that is <i>index</i> >= 0 && * <i>index</i> < getRootCount()). * * @return the root of at index <I>index</I> */ public Object getRootAt(int index) { return roots.get(index); } /** * Returns the index of <code>root</code> in the model. * If root is <code>null</code>, returns -1. * @param root a root in the model, obtained from this data source * @return the index of the root in the model, or -1 * if the parent is <code>null</code> */ public int getIndexOfRoot(Object root) { return roots.indexOf(root); } /** * Returns <code>true</code> if <code>node</code> or one of its * ancestors is in the model. * * @return <code>true</code> if <code>node</code> is in the model */ public boolean contains(Object node) { Object parentNode = null; while ((parentNode = getParent(node)) != null) node = parentNode; return roots.contains(node); } /** * Returns a <code>Map</code> that represents the attributes for * the specified cell. This attributes have precedence over each * view's attributes, regardless of isAttributeStore. * * @return attributes of <code>node</code> as a <code>Map</code> */ public AttributeMap getAttributes(Object node) { if (node instanceof GraphCell) return ((GraphCell) node).getAttributes(); return null; } /** * @return Returns the user object of the given cell. This implementation * checks if the cell is a default mutable tree node and returns * it's user object. */ public Object getValue(Object cell) { if (cell instanceof DefaultMutableTreeNode) return ((DefaultMutableTreeNode) cell).getUserObject(); return null; } // // Graph Structure // /** * Returns the source of <code>edge</code>. <I>edge</I> must be an object * previously obtained from this data source. * * @return <code>Object</code> that represents the source of <i>edge</i> */ public Object getSource(Object edge) { if (edge instanceof Edge) return ((Edge) edge).getSource(); return null; } /** * Returns the target of <code>edge</code>. <I>edge</I> must be an object * previously obtained from this data source. * * @return <code>Object</code> that represents the target of <i>edge</i> */ public Object getTarget(Object edge) { if (edge instanceof Edge) return ((Edge) edge).getTarget(); return null; } /** * Returns <code>true</code> if <code>port</code> is a valid source * for <code>edge</code>. <I>edge</I> and <I>port</I> must be * objects previously obtained from this data source. * * @return <code>true</code> if <code>port</code> is a valid source * for <code>edge</code>. */ public boolean acceptsSource(Object edge, Object port) { return true; } /** * Returns <code>true</code> if <code>port</code> is a valid target * for <code>edge</code>. <I>edge</I> and <I>port</I> must be * objects previously obtained from this data source. * * @return <code>true</code> if <code>port</code> is a valid target * for <code>edge</code>. */ public boolean acceptsTarget(Object edge, Object port) { return true; } /** * Returns an iterator of the edges connected to <code>port</code>. * <I>port</I> must be a object previously obtained from * this data source. This method never returns null. * * @param port a port in the graph, obtained from this data source * @return <code>Iterator</code> that represents the connected edges */ public Iterator edges(Object port) { if (port instanceof Port) return ((Port) port).edges(); return emptyIterator; } /** * Returns <code>true</code> if <code>edge</code> is a valid edge. * * @return <code>true</code> if <code>edge</code> is a valid edge. */ public boolean isEdge(Object edge) { return edge instanceof Edge; } /** * Returns <code>true</code> if <code>port</code> is a valid * port, possibly supporting edge connection. * * @return <code>true</code> if <code>port</code> is a valid port. */ public boolean isPort(Object port) { return port instanceof Port; } // // Group Structure // /** * Returns a map of (cell, clone)-pairs for all <code>cells</code> * and their children. Special care is taken to replace the anchor * references between ports. (Iterative implementation.) */ public Map cloneCells(Object[] cells) { Map map = new Hashtable(); // Add Cells to Queue ArrayList q = new ArrayList(); for (int i = 0; i < cells.length; i++) q.add(cells[i]); // Iterate Queue while (!q.isEmpty()) { // Remove Front Client From Queue Object node = q.remove(0); if (!map.containsKey(node)) { Object parent = getParent(node); if (parent != null) parent = map.get(parent); Object clone = cloneCell(node, parent); map.put(node, clone); } } // Replace Anchors Iterator it = map.values().iterator(); while (it.hasNext()) { Object obj = it.next(); // For All Ports in Result Map do... if (obj instanceof Port) { Object anchor = ((Port) obj).getAnchor(); // Map Anchor to Cloned Anchor if (anchor != null) ((Port) obj).setAnchor((Port) map.get(anchor)); } } return map; } /** * Creates a shallow copy of the cell including a copy of the user object * and a reference to the parent (which is a clone of the old parent or * null). Subclassers can override the cloneUserObject to provide a custom * user object cloning mechanism. */ protected Object cloneCell(Object cellObj, Object parent) { if (cellObj instanceof DefaultMutableTreeNode && (parent == null || parent instanceof DefaultMutableTreeNode)) { // Clone the cell DefaultGraphCell cell = (DefaultGraphCell) cellObj; DefaultGraphCell clone = (DefaultGraphCell) cell.clone(); // Add to parent if (parent != null) { DefaultMutableTreeNode parentNode = (DefaultMutableTreeNode) parent; parentNode.add(clone); } // Clone the user object clone.setUserObject(cloneUserObject(cell.getUserObject())); return clone; } return cellObj; } /** * Clones the user object. Helper method that is invoked from cloneCells. * You must use cloneCells (or cloneCell for single cells) to get a deep * copy of a clone. Subclassers must override this and valueForCellChanged * to implement custom user objects. This implementation returns * <code>object</code>. */ protected Object cloneUserObject(Object userObject) { if (userObject instanceof org.enhydra.shark.xpdl.XMLComplexElement) return ((org.enhydra.shark.xpdl.XMLComplexElement) userObject).clone(); return userObject; } /** * Returns the parent of <I>child</I> in the model. * <I>child</I> must be a node previously obtained from * this data source. This returns null if <i>child</i> is * a root in the model. * * @param child a node in the graph, obtained from this data source * @return the parent of <I>child</I> */ public Object getParent(Object child) { if (child != null && child instanceof TreeNode) return ((TreeNode) child).getParent(); return null; } /** * Returns the index of child in parent. * If either the parent or child is <code>null</code>, returns -1. * @param parent a note in the tree, obtained from this data source * @param child the node we are interested in * @return the index of the child in the parent, or -1 * if either the parent or the child is <code>null</code> */ public int getIndexOfChild(Object parent, Object child) { if (parent == null || child == null) return -1; return ((TreeNode) parent).getIndex((TreeNode) child); } /** * Returns the child of <I>parent</I> at index <I>index</I> in the parent's * child array. <I>parent</I> must be a node previously obtained from * this data source. This should not return null if <i>index</i> * is a valid index for <i>parent</i> (that is <i>index</i> >= 0 && * <i>index</i> < getChildCount(<i>parent</i>)). * * @param parent a node in the tree, obtained from this data source * @return the child of <I>parent</I> at index <I>index</I> */ public Object getChild(Object parent, int index) { if (parent instanceof TreeNode) return ((TreeNode) parent).getChildAt(index); return null; } /** * Returns the number of children of <I>parent</I>. Returns 0 if the node * is a leaf or if it has no children. <I>parent</I> must be a node * previously obtained from this data source. * * @param parent a node in the tree, obtained from this data source * @return the number of children of the node <I>parent</I> */ public int getChildCount(Object parent) { if (parent instanceof TreeNode) return ((TreeNode) parent).getChildCount(); return 0; } /** * Returns whether the specified node is a leaf node. * The way the test is performed depends on the. * * @param node the node to check * @return true if the node is a leaf node */ public boolean isLeaf(Object node) { if (asksAllowsChildren && node instanceof TreeNode) return !((TreeNode) node).getAllowsChildren(); return ((TreeNode) node).isLeaf(); } // // Change Support // /** * Inserts the <code>roots</code> and connections into the model. * Notifies the model- and undo listeners of the change. The passed-in * edits are executed if they implement the * <code>GraphModelEvent.ExecutableGraphChange</code> interface * in ascending array-order, after execution of the model change. * (Note: The external order is important in a * special case: After insertion on a partial view, ie. one that does not * display all cells of the model, the cell is made visible after * it is inserted into the model. This requires the inserting view * to be able to add the cell to the visible set before it is * inserted into the model.) * Note: The passed-in propertyMap may contains PortViews * which must be turned into Points when stored in the model. */ public void insert(Object[] pRoots, Map pAttributes, ConnectionSet pCs, ParentMap pPm, UndoableEdit[] pEdits) { String undoMsg = ResourceManager.getLanguageDependentString("MessageInsertingObjects"); GraphModelEdit edit = createInsertEdit(pRoots, pAttributes, pCs, pPm, pEdits, undoMsg); if (edit != null) { edit.execute(); if (pEdits != null) { for (int i = 0; i < pEdits.length; i++) if (pEdits[i] instanceof GraphLayoutCache.GraphLayoutCacheEdit) ((GraphLayoutCache.GraphLayoutCacheEdit) pEdits[i]).execute(); } postEdit(edit); } } /** * Removes <code>cells</code> from the model. * Notifies the model- and undo listeners of the change. */ public void remove(Object[] pRoots) { String undoMsg = ResourceManager.getLanguageDependentString("MessageRemovingObjects"); GraphModelEdit edit = createRemoveEdit(pRoots, undoMsg); if (edit != null) { edit.execute(); postEdit(edit); } } /** * Applies <code>attributes</code> and the connection changes to * the model. The initial <code>edits</code> that triggered the call * are considered to be part of this transaction. The passed-in * edits are executed if they implement the * <code>GraphModelEvent.ExecutableGraphChange</code> interface * in ascending array-order, after execution of the model change. * Notifies the model- and undo listeners of the change. * <strong>Note:</strong> If only <code>edits</code> is non-null, the * edits are directly passed to the UndoableEditListeners. * Note: The passed-in propertyMap may contains PortViews * which must be turned into Points when stored in the model. */ public void edit(Map attributes, ConnectionSet cs, ParentMap pm, UndoableEdit[] edits) { if ((attributes == null || attributes.isEmpty()) && (cs == null || cs.isEmpty()) && pm == null && edits != null && edits.length == 1) { if (edits[0] instanceof GraphLayoutCache.GraphLayoutCacheEdit) ((GraphLayoutCache.GraphLayoutCacheEdit) edits[0]).execute(); postEdit(edits[0]); // UndoableEdit Relay } else { String undoMsg = ResourceManager.getLanguageDependentString("MessageEditingObject"); GraphModelEdit edit = createCellEdit(attributes, cs, pm, edits, undoMsg); //System.out.println("DefaultGraphModel_edit_attributes="+attributes); if (edit != null) { edit.execute(); if (edits != null) { for (int i = 0; i < edits.length; i++) if (edits[i] instanceof GraphLayoutCache.GraphLayoutCacheEdit) ((GraphLayoutCache.GraphLayoutCacheEdit) edits[i]).execute(); } postEdit(edit); } } } /** * Used for editing font sizes without haveing an undo action set. */ public void editFonts(Map attributes) { GraphModelEdit edit = createCellEdit(attributes, null, null, null, null); //System.out.println("DefaultGraphModel_edit_attributes="+attributes); if (edit != null) { edit.execute(); } } /** * Used for editing font sizes without haveing an undo action set. */ public void removeBubbles(Object[] bubbles, GraphModelListener gml) { removeGraphModelListener(gml); GraphModelEdit edit = createRemoveEdit(bubbles, null); if (edit != null) { edit.execute(); } addGraphModelListener(gml); } /**
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -