| Line | Hits | Source |
|---|---|---|
| 1 | /* | |
| 2 | * Copyright (c) 2003, the JUNG Project and the Regents of the University of | |
| 3 | * California All rights reserved. | |
| 4 | * | |
| 5 | * This software is open-source under the BSD license; see either "license.txt" | |
| 6 | * or http://jung.sourceforge.net/license.txt for a description. | |
| 7 | */ | |
| 8 | package edu.uci.ics.jung.visualization.graphdraw; | |
| 9 | ||
| 10 | import java.awt.BasicStroke; | |
| 11 | import java.awt.Color; | |
| 12 | import java.awt.Graphics; | |
| 13 | import java.awt.Graphics2D; | |
| 14 | import java.awt.Stroke; | |
| 15 | ||
| 16 | import edu.uci.ics.jung.graph.DirectedEdge; | |
| 17 | import edu.uci.ics.jung.graph.Edge; | |
| 18 | import edu.uci.ics.jung.graph.UndirectedEdge; | |
| 19 | import edu.uci.ics.jung.graph.Vertex; | |
| 20 | import edu.uci.ics.jung.graph.decorators.EdgeColorFunction; | |
| 21 | import edu.uci.ics.jung.graph.decorators.EdgeStringer; | |
| 22 | import edu.uci.ics.jung.graph.decorators.EdgeThicknessFunction; | |
| 23 | import edu.uci.ics.jung.graph.decorators.StringLabeller; | |
| 24 | import edu.uci.ics.jung.graph.decorators.VertexColorFunction; | |
| 25 | import edu.uci.ics.jung.graph.predicates.EdgePredicate; | |
| 26 | import edu.uci.ics.jung.graph.predicates.SelfLoopEdgePredicate; | |
| 27 | import edu.uci.ics.jung.visualization.AbstractRenderer; | |
| 28 | import edu.uci.ics.jung.visualization.contrib.Arrow; | |
| 29 | ||
| 30 | /** | |
| 31 | * A renderer with all sorts of buttons to press and dials to turn. In general, | |
| 32 | * if a function is available to get an answer to questions of color. Otherwise, | |
| 33 | * the set fields are used. | |
| 34 | * <p> | |
| 35 | * The default is to paint vertices with Black foreground text and Red | |
| 36 | * backgrounds. Picked vertices are orange. [Whether a vertex is Picked is | |
| 37 | * resolved with <tt>v.getUserDatum(_VisualizationViewer.VIS_KEY);</tt>] | |
| 38 | * | |
| 39 | * <p> | |
| 40 | * Note that setting a stroke width other than 1 is likely to slow down the | |
| 41 | * visualization noticably, as is using transparency. | |
| 42 | * | |
| 43 | * @deprecated Replaced by PluggableRenderer. | |
| 44 | * @author danyelf | |
| 45 | */ | |
| 46 | public class SettableRenderer extends AbstractRenderer { | |
| 47 | ||
| 48 | 0 | protected Color vertexFGColor = Color.BLACK; |
| 49 | ||
| 50 | 0 | protected Color vertexPickedColor = Color.ORANGE; |
| 51 | ||
| 52 | 0 | protected Color vertexBGColor = Color.RED; |
| 53 | ||
| 54 | protected VertexColorFunction vertexColorFunction; | |
| 55 | ||
| 56 | protected EdgeThicknessFunction edgeThicknessFunction; | |
| 57 | ||
| 58 | protected int edgeThickness; | |
| 59 | ||
| 60 | 0 | protected Color edgeColor = Color.BLACK; |
| 61 | ||
| 62 | protected EdgeColorFunction edgeColorFunction; | |
| 63 | ||
| 64 | protected StringLabeller mStringLabeller; | |
| 65 | ||
| 66 | 0 | protected boolean mShouldDrawSelfLoops = false; |
| 67 | ||
| 68 | 0 | protected boolean mDrawLightBoxes = true; |
| 69 | ||
| 70 | 0 | protected boolean mShouldDrawArrowsUndirected = false; |
| 71 | ||
| 72 | 0 | protected boolean mShouldDrawArrowsDirected = true; |
| 73 | ||
| 74 | protected Arrow mArrow; | |
| 75 | ||
| 76 | protected EdgeStringer mEdgeLabelFunction; | |
| 77 | ||
| 78 | protected int mLineHeight; | |
| 79 | ||
| 80 | 0 | protected static EdgePredicate self_loop = SelfLoopEdgePredicate.getInstance(); |
| 81 | ||
| 82 | /** | |
| 83 | * This variant simply renders vertices as small empty boxes without labels. | |
| 84 | */ | |
| 85 | 0 | public SettableRenderer() { |
| 86 | 0 | this.mStringLabeller = null; |
| 87 | 0 | } |
| 88 | ||
| 89 | /** | |
| 90 | * Creates a SettableRenderer that will be drawn in the "heavy" style: a box | |
| 91 | * around the label | |
| 92 | * | |
| 93 | * @param sl | |
| 94 | */ | |
| 95 | 0 | public SettableRenderer(StringLabeller sl) { |
| 96 | 0 | this.mStringLabeller = sl; |
| 97 | 0 | } |
| 98 | ||
| 99 | /** | |
| 100 | * Creates a SettableRenderer that will label edges with the given EdgeStringer. | |
| 101 | * (You may want EdgeWeightLabellerStringer, which uses an EdgeWeightLabeller to | |
| 102 | * label the weights.) | |
| 103 | * @param sl | |
| 104 | * @param el | |
| 105 | */ | |
| 106 | 0 | public SettableRenderer(StringLabeller sl, EdgeStringer el) { |
| 107 | 0 | this.mStringLabeller = sl; |
| 108 | 0 | this.mEdgeLabelFunction = el; |
| 109 | 0 | } |
| 110 | ||
| 111 | /** | |
| 112 | * Creates a SettableRenderer that will be drawn in the "light" style: a | |
| 113 | * colored box next to text, instead of text overlaying the box. | |
| 114 | */ | |
| 115 | public void setLightDrawing(boolean b) { | |
| 116 | 0 | this.mDrawLightBoxes = b; |
| 117 | 0 | } |
| 118 | ||
| 119 | public void setStringLabeller(StringLabeller sl) { | |
| 120 | 0 | this.mStringLabeller = sl; |
| 121 | 0 | } |
| 122 | ||
| 123 | public void setEdgeColor(Color c) { | |
| 124 | 0 | edgeColor = c; |
| 125 | 0 | } |
| 126 | ||
| 127 | /** | |
| 128 | * Edges are drawn by calling <tt>EdgeColorFunction</tt> with the edge, to | |
| 129 | * decide how it is to be drawn. | |
| 130 | * | |
| 131 | * @param ecf | |
| 132 | */ | |
| 133 | public void setEdgeColorFunction(EdgeColorFunction ecf) { | |
| 134 | 0 | this.edgeColorFunction = ecf; |
| 135 | 0 | } |
| 136 | ||
| 137 | /** | |
| 138 | * Forces all edges to draw with this thickness. Sets the edge thickness | |
| 139 | * function to null. | |
| 140 | * | |
| 141 | * @param i | |
| 142 | */ | |
| 143 | public void setEdgeThickness(int i) { | |
| 144 | 0 | this.edgeThicknessFunction = null; |
| 145 | 0 | this.edgeThickness = i; |
| 146 | 0 | } |
| 147 | ||
| 148 | /** | |
| 149 | * This version takes a function that dynamically chooses an edge thickness. | |
| 150 | * | |
| 151 | * @param etf | |
| 152 | */ | |
| 153 | public void setEdgeThicknessFunction(EdgeThicknessFunction etf) { | |
| 154 | 0 | this.edgeThicknessFunction = etf; |
| 155 | 0 | this.edgeThickness = 0; |
| 156 | 0 | } |
| 157 | ||
| 158 | /** | |
| 159 | * Sets whether the system should draw arrows on directed edges. By default, | |
| 160 | * yes. | |
| 161 | * | |
| 162 | * @param b | |
| 163 | */ | |
| 164 | public void setShouldDrawDirectedArrows(boolean b) { | |
| 165 | 0 | this.mShouldDrawArrowsDirected = b; |
| 166 | 0 | } |
| 167 | ||
| 168 | /** | |
| 169 | * Sets whether the system should draw arrows on directed edges. By default, | |
| 170 | * yes. | |
| 171 | * | |
| 172 | * @param b | |
| 173 | */ | |
| 174 | public void setShouldDrawUndirectedArrows(boolean b) { | |
| 175 | 0 | this.mShouldDrawArrowsUndirected = b; |
| 176 | 0 | } |
| 177 | ||
| 178 | /** | |
| 179 | * Sets whether the system should draw self-loops. By default, no. | |
| 180 | * @param b | |
| 181 | */ | |
| 182 | public void setShouldDrawSelfLoops( boolean b ) { | |
| 183 | 0 | this.mShouldDrawSelfLoops = b; |
| 184 | 0 | } |
| 185 | ||
| 186 | /** | |
| 187 | * Paints the edge in the color specified by the EdgeColorFunction or the | |
| 188 | * hard-set color, and at the thickness set with an | |
| 189 | * <tt>EdgeThicknessFunction</tt>. Draws a self-loop if | |
| 190 | * <tt>shouldDrawSelfLoops()</tt> has been set (by default, no); draws an | |
| 191 | * arrow on directed edges if <tt>shouldDrawDirectedArrows()</tt> has been | |
| 192 | * set (by default, yes) and on both ends of undirected edges if | |
| 193 | * <tt>shouldDrawUndirectedArrows()</tt> has been set (by default, false). | |
| 194 | * Calls either drawEdge or drawEdgeSimple. Draws one arrow for | |
| 195 | * self-loops if needed. Note that x1, y1 always correspond to | |
| 196 | * e.getEndpoints.getFirst() and x2, y2 always correspond to | |
| 197 | * e.getEndpoints.getSecond() | |
| 198 | * | |
| 199 | * @see EdgeThicknessFunction EdgeThicknessFunction | |
| 200 | * @see EdgeColorFunction EdgeColorFunction | |
| 201 | */ | |
| 202 | public void paintEdge(Graphics g, Edge e, int x1, int y1, int x2, int y2) { | |
| 203 | 0 | Graphics2D g2d = (Graphics2D) g; |
| 204 | 0 | mLineHeight = g2d.getFontMetrics().getHeight(); |
| 205 | ||
| 206 | float edgeWidth; | |
| 207 | 0 | if (edgeThicknessFunction != null) |
| 208 | 0 | edgeWidth = edgeThicknessFunction.getEdgeThickness(e); |
| 209 | else | |
| 210 | 0 | edgeWidth = edgeThickness; |
| 211 | ||
| 212 | 0 | if (edgeColorFunction == null) { |
| 213 | 0 | g.setColor(edgeColor); |
| 214 | } else { | |
| 215 | 0 | g.setColor(edgeColorFunction.getEdgeColor(e)); |
| 216 | } | |
| 217 | ||
| 218 | 0 | if (edgeWidth == 1) |
| 219 | 0 | drawEdgeSimple(g, e, x1, y1, x2, y2); |
| 220 | else | |
| 221 | 0 | drawEdge(edgeWidth, g, e, x1, y1, x2, y2); |
| 222 | ||
| 223 | 0 | if (mShouldDrawArrowsDirected && e instanceof DirectedEdge) { |
| 224 | 0 | drawArrowhead(g2d, e, x1, y1, x2, y2); |
| 225 | } | |
| 226 | 0 | if (mShouldDrawArrowsUndirected && e instanceof UndirectedEdge) { |
| 227 | 0 | drawArrowhead(g2d, e, x1, y1, x2, y2); |
| 228 | 0 | drawArrowhead(g2d, e, x2, y2, x1, y1); |
| 229 | } | |
| 230 | ||
| 231 | 0 | String label = (mEdgeLabelFunction == null) ? null : mEdgeLabelFunction |
| 232 | .getLabel(e); | |
| 233 | 0 | if (label != null) { |
| 234 | 0 | labelEdge(g2d, e, label, x1, x2, y1, y2); |
| 235 | } | |
| 236 | 0 | } |
| 237 | ||
| 238 | /** | |
| 239 | * Labels the edge at the half-way point (if undirected) or three-quarters | |
| 240 | * if directed or 15 pixels above the vertex if self-loop. | |
| 241 | * | |
| 242 | * @param g2d | |
| 243 | * @param e | |
| 244 | * @param label | |
| 245 | * @param x1 | |
| 246 | * @param x2 | |
| 247 | * @param y1 | |
| 248 | * @param y2 | |
| 249 | */ | |
| 250 | public void labelEdge(Graphics2D g2d, Edge e, String label, int x1, int x2, | |
| 251 | int y1, int y2) { | |
| 252 | ||
| 253 | 0 | if (self_loop.evaluate(e)) { |
| 254 | 0 | g2d.drawString(label, x1 - 3 , y1 - 10 - mLineHeight/2); |
| 255 | 0 | return; |
| 256 | } | |
| 257 | ||
| 258 | 0 | int distX = x2 - x1; |
| 259 | 0 | int distY = y2 - y1; |
| 260 | 0 | double totalLength = Math.sqrt(distX * distX + distY * distY); |
| 261 | ||
| 262 | //closeness is a double in the range [0,1] that represents | |
| 263 | //how close to the target vertex the edge weight should be | |
| 264 | //drawn (0 means "on the source vertex", 1 means "on the target | |
| 265 | // vertex") | |
| 266 | //weights of undirected edges should be drawn at 0.5 (in the middle of | |
| 267 | // the edge) | |
| 268 | double closeness; | |
| 269 | 0 | if (e instanceof DirectedEdge) { |
| 270 | 0 | closeness = 0.73; |
| 271 | } else { | |
| 272 | 0 | closeness = 0.5; |
| 273 | } | |
| 274 | ||
| 275 | 0 | int posX = (int) (x1 + (closeness) * distX); |
| 276 | 0 | int posY = (int) (y1 + (closeness) * distY); |
| 277 | ||
| 278 | 0 | int LEN = 10; |
| 279 | 0 | int xDisplacement = (int) (LEN * (-distY / totalLength)); |
| 280 | 0 | int yDisplacement = (int) (LEN * (distX / totalLength)); |
| 281 | 0 | g2d.drawString(label, posX + xDisplacement, posY + yDisplacement + mLineHeight / 2); |
| 282 | 0 | } |
| 283 | ||
| 284 | /** | |
| 285 | * Draws an arrowhead on this edge in the direction from xsource,ysource to | |
| 286 | * xend, yend | |
| 287 | */ | |
| 288 | protected void drawArrowhead(Graphics2D g2d, Edge e, int xsource, | |
| 289 | int ysource, int xdest, int ydest) { | |
| 290 | ||
| 291 | 0 | if (mArrow == null) { |
| 292 | 0 | mArrow = new Arrow(Arrow.CLASSIC, 7, 9); |
| 293 | } | |
| 294 | ||
| 295 | 0 | if (mShouldDrawSelfLoops && self_loop.evaluate(e)) { |
| 296 | 0 | mArrow.drawArrow(g2d, xsource - 10, ysource - 5, xsource, ysource, 15); |
| 297 | 0 | return; |
| 298 | } | |
| 299 | ||
| 300 | 0 | if (mDrawLightBoxes) { |
| 301 | 0 | mArrow.drawArrow(g2d, xsource, ysource, xdest, ydest, 12); |
| 302 | } else { | |
| 303 | 0 | mArrow.drawArrow(g2d, xsource, ysource, xdest, ydest, 16); |
| 304 | } | |
| 305 | ||
| 306 | 0 | } |
| 307 | ||
| 308 | /** | |
| 309 | * Draws the edge at the given width, then restores the previous stroke. | |
| 310 | * Calls drawEdgeSimple to accomplish this task. | |
| 311 | * | |
| 312 | * @param edgeWidth | |
| 313 | * the width of the stroke. | |
| 314 | */ | |
| 315 | protected void drawEdge(float edgeWidth, Graphics g, Edge e, int x1, | |
| 316 | int y1, int x2, int y2) { | |
| 317 | 0 | Graphics2D g2d = (Graphics2D) g; |
| 318 | ||
| 319 | 0 | Stroke previous = g2d.getStroke(); |
| 320 | ||
| 321 | // if (Math.floor(edgeWidth) == edgeWidth) { | |
| 322 | // if (strokeTable[(int) edgeWidth] == null) { | |
| 323 | // Stroke s = new BasicStroke(edgeWidth); | |
| 324 | // strokeTable[(int) edgeWidth] = s; | |
| 325 | // g2d.setStroke(strokeTable[(int) edgeWidth]); | |
| 326 | // } else { | |
| 327 | 0 | g2d.setStroke(new BasicStroke(edgeWidth)); |
| 328 | // } | |
| 329 | // } | |
| 330 | 0 | drawEdgeSimple(g, e, x1, y1, x2, y2); |
| 331 | 0 | g2d.setStroke(previous); |
| 332 | 0 | } |
| 333 | ||
| 334 | protected void drawEdgeSimple(Graphics g, Edge e, int x1, int y1, int x2, | |
| 335 | int y2) { | |
| 336 | ||
| 337 | 0 | if (mShouldDrawSelfLoops && self_loop.evaluate(e)) { |
| 338 | // self-loops | |
| 339 | 0 | g.drawOval(x1 - 15, y1 - 30, 30, 30); |
| 340 | } else { | |
| 341 | 0 | g.drawLine(x1, y1, x2, y2); |
| 342 | } | |
| 343 | 0 | } |
| 344 | ||
| 345 | /** | |
| 346 | * Manually sets the color of a Vertex's foreground (i.e. its text). | |
| 347 | * | |
| 348 | * @param vertexColor | |
| 349 | */ | |
| 350 | public void setVertexForegroundColor(Color vertexColor) { | |
| 351 | 0 | this.vertexFGColor = vertexColor; |
| 352 | 0 | } |
| 353 | ||
| 354 | /** | |
| 355 | * Manually sets the color of a picked Vertex's background (i.e. its field). | |
| 356 | * | |
| 357 | * @param vertexColor | |
| 358 | */ | |
| 359 | public void setVertexPickedColor(Color vertexColor) { | |
| 360 | 0 | this.vertexPickedColor = vertexColor; |
| 361 | 0 | } |
| 362 | ||
| 363 | /** | |
| 364 | * Manually sets the color of an unpicked Vertex's background (i.e. its | |
| 365 | * field). | |
| 366 | * | |
| 367 | * @param vertexColor | |
| 368 | */ | |
| 369 | public void setVertexBGColor(Color vertexColor) { | |
| 370 | 0 | this.vertexBGColor = vertexColor; |
| 371 | 0 | } |
| 372 | ||
| 373 | /** | |
| 374 | * Finds the color of a vertex with a VertexColorFunction. | |
| 375 | * | |
| 376 | * @param vcf | |
| 377 | */ | |
| 378 | public void setVertexColorFunction(VertexColorFunction vcf) { | |
| 379 | 0 | this.vertexColorFunction = vcf; |
| 380 | 0 | } |
| 381 | ||
| 382 | /** | |
| 383 | * Simple label function returns the StringLabeller's notion of v's label. | |
| 384 | * It may be sometimes useful to override this. | |
| 385 | * | |
| 386 | * @param v | |
| 387 | * a vertex | |
| 388 | * @return the label on the vertex. | |
| 389 | */ | |
| 390 | protected String getLabel(Vertex v) { | |
| 391 | 0 | if (mStringLabeller == null) return ""; |
| 392 | 0 | String s = mStringLabeller.getLabel(v); |
| 393 | 0 | if (s == null) { |
| 394 | 0 | return "?"; |
| 395 | } else { | |
| 396 | 0 | return s; |
| 397 | } | |
| 398 | } | |
| 399 | ||
| 400 | /** | |
| 401 | * Paints the vertex, using the settings above (VertexColors, etc). In this | |
| 402 | * implmenetation, vertices are painted as filled squares with textual | |
| 403 | * labels over the filled square. | |
| 404 | */ | |
| 405 | public void paintVertex(Graphics g, Vertex v, int x, int y) { | |
| 406 | 0 | String label = getLabel(v); |
| 407 | 0 | if (mDrawLightBoxes) { |
| 408 | 0 | paintLightVertex(g, v, x, y, label); |
| 409 | 0 | return; |
| 410 | } | |
| 411 | ||
| 412 | 0 | Color fg = (vertexColorFunction == null) ? vertexFGColor |
| 413 | : vertexColorFunction.getForeColor(v); | |
| 414 | ||
| 415 | 0 | if (vertexColorFunction == null) { |
| 416 | 0 | if (isPicked(v)) { |
| 417 | 0 | g.setColor(vertexPickedColor); |
| 418 | } else | |
| 419 | 0 | g.setColor(vertexBGColor); |
| 420 | } else { | |
| 421 | 0 | g.setColor(vertexColorFunction.getBackColor(v)); |
| 422 | } | |
| 423 | ||
| 424 | 0 | g.fillRect(x - 8, y - 6, g.getFontMetrics().stringWidth(label) + 8, 16); |
| 425 | 0 | g.setColor(fg); |
| 426 | 0 | g.drawString(label, x - 4, y + 6); |
| 427 | 0 | } |
| 428 | ||
| 429 | /** | |
| 430 | * @param g | |
| 431 | * @param v | |
| 432 | * @param x | |
| 433 | * @param y | |
| 434 | */ | |
| 435 | protected void paintLightVertex(Graphics g, Vertex v, int x, int y, | |
| 436 | String label) { | |
| 437 | Color bg; | |
| 438 | 0 | if (vertexColorFunction == null) { |
| 439 | 0 | if (isPicked(v)) { |
| 440 | 0 | bg = vertexPickedColor; |
| 441 | } else | |
| 442 | 0 | bg = vertexBGColor; |
| 443 | } else { | |
| 444 | 0 | bg = vertexColorFunction.getBackColor(v); |
| 445 | } | |
| 446 | ||
| 447 | 0 | Color fg = (vertexColorFunction == null) ? vertexFGColor |
| 448 | : vertexColorFunction.getForeColor(v); | |
| 449 | ||
| 450 | 0 | g.setColor(fg); |
| 451 | 0 | g.fillRect(x - 7, y - 7, 14, 14); |
| 452 | 0 | g.setColor(bg); |
| 453 | 0 | g.fillRect(x - 6, y - 6, 12, 12); |
| 454 | 0 | if (label.equals("?")) return; |
| 455 | 0 | g.setColor(fg); |
| 456 | 0 | g.drawString(label, x + 8, y + 6 ); // + g.getFontMetrics().getHeight()); |
| 457 | 0 | } |
| 458 | ||
| 459 | } |
|
this report was generated by version 1.0.5 of jcoverage. |
copyright © 2003, jcoverage ltd. all rights reserved. |