1 /* 2 * $Id: JGraphModelFacade.java,v 1.2 2010/01/29 17:04:29 david Exp $ 3 * Copyright (c) 2001-2006, Gaudenz Alder 4 * Copyright (c) 2005-2006, David Benson 5 * 6 * All rights reserved. 7 * 8 * This file is licensed under the JGraph software license, a copy of which 9 * will have been provided to you in the file LICENSE at the root of your 10 * installation directory. If you are unable to locate this file please 11 * contact JGraph sales for another copy. 12 */ 13 package com.jgraph.layout; 14 15 import java.awt.geom.Rectangle2D; 16 import java.util.ArrayList; 17 import java.util.Collections; 18 import java.util.HashSet; 19 import java.util.List; 20 import java.util.Set; 21 22 import org.jgraph.graph.DefaultGraphModel; 23 import org.jgraph.graph.GraphModel; 24 25 import com.jgraph.algebra.JGraphAlgebra; 26 import com.jgraph.algebra.cost.JGraphCostFunction; 27 import com.jgraph.algebra.cost.JGraphDistanceCostFunction; 28 29 /** 30 * An abstract description of a graph that can be used by a layout algorithm. 31 * This abstracts visibility, grouping, directed edges, any root cells, 32 * translation and scaling functions. It also stores the actual graph to be 33 * acted upon by the layout and provides utility method to determine the 34 * characteristics of the contained cells. After the layout has been applied 35 * this class stores the result of that layout as a nested attribute map. 36 * 37 */ 38 public class JGraphModelFacade extends JGraphFacade { 39 40 /** 41 * Constructs a JGraphGraphFacade specifying the graph passed in as the 42 * input graph 43 * 44 * @param model 45 * the GraphModel to be laid out 46 */ JGraphModelFacade(GraphModel model)47 public JGraphModelFacade(GraphModel model) { 48 this(model, null); 49 } 50 51 /** 52 * Constructs a JGraphGraphFacade specifying the graph passed in as the 53 * input graph 54 * 55 * @param model 56 * the JGraph to be laid out 57 * @param roots 58 * the root vertices to be used by tree layouts. This is not the 59 * same thing as the roots of the graph model. 60 */ JGraphModelFacade(GraphModel model, Object[] roots)61 public JGraphModelFacade(GraphModel model, Object[] roots) { 62 this(model, roots, true, false, true, true); 63 } 64 65 /** 66 * Constructs a JGraphGraphFacade 67 * 68 * @see #JGraphModelFacade(GraphModel, Object[], boolean, boolean, boolean, boolean, 69 * JGraphCostFunction, JGraphAlgebra) 70 */ JGraphModelFacade(GraphModel model, Object[] roots, boolean ignoresHiddenCells, boolean ignoresCellsInGroups, boolean ignoresUnconnectedCells, boolean directed)71 public JGraphModelFacade(GraphModel model, Object[] roots, 72 boolean ignoresHiddenCells, boolean ignoresCellsInGroups, 73 boolean ignoresUnconnectedCells, boolean directed) { 74 this(model, roots, ignoresHiddenCells, ignoresCellsInGroups, 75 ignoresUnconnectedCells, directed, 76 new JGraphDistanceCostFunction(null), 77 JGraphAlgebra.getSharedInstance()); 78 } 79 80 /** 81 * Creates a JGraphGraphFacade specifying the graph passed in as the input 82 * graph. Also configures properties of layout, whether or not edge 83 * direction is to be taken into account, whether or not invisible cells are 84 * to be considered and whether or not only root cells are to be considered 85 * or roots and all their children. A root is only used if the isVertex 86 * method returns true. 87 * 88 * @see #isVertex 89 * 90 * @param model 91 * The graph used as input to the layout 92 * @param roots 93 * the root vertices to be used by tree layouts 94 * @param ignoresHiddenCells 95 * @see #ignoresHiddenCells 96 * @param ignoresCellsInGroups 97 * @see #ignoresCellsInGroups 98 * @param ignoresUnconnectedCells 99 * @see #ignoresUnconnectedCells 100 * @param directed 101 * @see #directed 102 * @param distanceCostFunction 103 * the cost function that defines the distance metrics 104 * @param algebra 105 * the algebra used for basic algorithms and functions 106 */ JGraphModelFacade(GraphModel model, Object[] roots, boolean ignoresHiddenCells, boolean ignoresCellsInGroups, boolean ignoresUnconnectedCells, boolean directed, JGraphCostFunction distanceCostFunction, JGraphAlgebra algebra)107 public JGraphModelFacade(GraphModel model, Object[] roots, 108 boolean ignoresHiddenCells, boolean ignoresCellsInGroups, 109 boolean ignoresUnconnectedCells, boolean directed, 110 JGraphCostFunction distanceCostFunction, JGraphAlgebra algebra) { 111 super(model, roots, ignoresHiddenCells, ignoresCellsInGroups, 112 ignoresUnconnectedCells, directed, distanceCostFunction, 113 algebra); 114 } 115 116 /** 117 * A shortcut method that calls getNeighbours with no cells to exclude. 118 * 119 * @see #getNeighbours(Object, Set, boolean) 120 */ getNeighbours(Object cell, boolean ordered)121 public List getNeighbours(Object cell, boolean ordered) { 122 return getNeighbours(cell, null, ordered); 123 } 124 125 /** 126 * Returns a collection of cells that are connected to the specified cell by 127 * edges. Any cells specified in the exclude set will be ignored. 128 * 129 * @param cell 130 * The cell from which the neighbours will be determined 131 * @param exclude 132 * The set of cells to ignore when searching 133 * @param ordered 134 * whether or not to order the returned value in the order of the 135 * current <code>order</code> comparator. <b>Be very careful</b> 136 * using the default comparator on the default graph model, 137 * <code>getIndexOfRoot</code> has linear performance and so 138 * sorting the entire model roots will have quadratic 139 * performance. 140 * @return Returns the set of neighbours for <code>cell</code> 141 */ getNeighbours(Object cell, Set exclude, boolean ordered)142 public List getNeighbours(Object cell, Set exclude, boolean ordered) { 143 Object[] fanout = (directed) ? DefaultGraphModel.getOutgoingEdges( 144 model, cell) : DefaultGraphModel.getEdges(model, 145 new Object[] { cell }).toArray(); 146 List connectedCells = new ArrayList(fanout.length); 147 Set localExclude = new HashSet(fanout.length + 8, (float) 0.75); 148 for (int i = 0; i < fanout.length; i++) { 149 Object neighbour = DefaultGraphModel.getOpposite(model, fanout[i], 150 cell); 151 if (neighbour != null 152 && (exclude == null || !exclude.contains(neighbour)) 153 && !localExclude.contains(neighbour)) { 154 localExclude.add(neighbour); 155 connectedCells.add(neighbour); 156 } 157 } 158 if (ordered && order != null) 159 Collections.sort(connectedCells, order); 160 return connectedCells; 161 } 162 163 /** 164 * Returns the outgoing edges for cell. Cell should be a port or a vertex. 165 * 166 * @param cell 167 * The cell from which the outgoing edges will be determined 168 * @param exclude 169 * The set of edges to ignore when searching 170 * @param visibleCells 171 * whether or not only visible cells should be processed 172 * @param selfLoops 173 * whether or not to include self loops in the returned list 174 * @return Returns the list of outgoing edges for <code>cell</code> 175 */ getOutgoingEdges(Object cell, Set exclude, boolean visibleCells, boolean selfLoops)176 public List getOutgoingEdges(Object cell, Set exclude, 177 boolean visibleCells, boolean selfLoops) { 178 Object[] edges = DefaultGraphModel.getEdges(model, cell, false); 179 180 List edgeList = new ArrayList(edges.length); 181 Set localExclude = new HashSet(edges.length); 182 for (int i = 0; i < edges.length; i++) { 183 // Check that the edge is neiter in the passed in exclude set or 184 // the local exclude set. Also, if visibleCells is true check 185 // the edge is visible in the cache. 186 if ((exclude == null || !exclude.contains(edges[i])) 187 && !localExclude.contains(edges[i])) { 188 // Add the edge to the list if all edges, including self loops 189 // are allowed. If self loops are not allowed, ensure the 190 // source and target of the edge are different 191 if (selfLoops == true 192 || model.getSource(edges[i]) != model 193 .getTarget(edges[i])) { 194 edgeList.add(edges[i]); 195 } 196 localExclude.add(edges[i]); 197 } 198 } 199 return edgeList; 200 } 201 202 /** 203 * Returns the incoming edges for cell. Cell should be a port or a vertex. 204 * 205 * @param cell 206 * The cell from which the incoming edges will be determined 207 * @param exclude 208 * The set of edges to ignore when searching 209 * @param visibleCells 210 * whether or not only visible cells should be processed 211 * @param selfLoops 212 * whether or not to include self loops in the returned list 213 * @return Returns the list of incoming edges for <code>cell</code> 214 */ getIncomingEdges(Object cell, Set exclude, boolean visibleCells, boolean selfLoops)215 public List getIncomingEdges(Object cell, Set exclude, 216 boolean visibleCells, boolean selfLoops) { 217 Object[] edges = DefaultGraphModel.getEdges(model, cell, true); 218 219 List edgeList = new ArrayList(edges.length); 220 Set localExclude = new HashSet(edges.length); 221 for (int i = 0; i < edges.length; i++) { 222 // Check that the edge is neiter in the passed in exclude set or 223 // the local exclude set. Also, if visibleCells is true check 224 // the edge is visible in the cache. 225 if ((exclude == null || !exclude.contains(edges[i])) 226 && !localExclude.contains(edges[i])) { 227 // Add the edge to the list if all edges, including self loops 228 // are allowed. If self loops are not allowed, ensure the 229 // source and target of the edge are different 230 if (selfLoops == true 231 || model.getSource(edges[i]) != model 232 .getTarget(edges[i])) { 233 edgeList.add(edges[i]); 234 } 235 localExclude.add(edges[i]); 236 } 237 } 238 return edgeList; 239 } 240 241 /** 242 * Returns the minimal rectangular bounds that enclose all the elements in 243 * the <code>bounds</code> map. After a layout has completed this method 244 * will return the collective bounds of the new laid out graph. 245 * 246 * @return <code>null</code> 247 */ getGraphBounds()248 public Rectangle2D getGraphBounds() { 249 return getCellBounds(); 250 } 251 } 252