| 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 | * Created on Feb 2, 2005 | |
| 8 | * | |
| 9 | */ | |
| 10 | package edu.uci.ics.jung.visualization; | |
| 11 | ||
| 12 | import java.awt.BorderLayout; | |
| 13 | import java.awt.Dimension; | |
| 14 | import java.awt.Rectangle; | |
| 15 | import java.awt.event.AdjustmentEvent; | |
| 16 | import java.awt.event.AdjustmentListener; | |
| 17 | import java.awt.event.ComponentAdapter; | |
| 18 | import java.awt.event.ComponentEvent; | |
| 19 | import java.awt.geom.AffineTransform; | |
| 20 | import java.awt.geom.Line2D; | |
| 21 | import java.awt.geom.Point2D; | |
| 22 | import java.util.Set; | |
| 23 | ||
| 24 | import javax.swing.BoundedRangeModel; | |
| 25 | import javax.swing.JComponent; | |
| 26 | import javax.swing.JPanel; | |
| 27 | import javax.swing.JScrollBar; | |
| 28 | import javax.swing.event.ChangeEvent; | |
| 29 | import javax.swing.event.ChangeListener; | |
| 30 | ||
| 31 | import edu.uci.ics.jung.visualization.transform.Transformer; | |
| 32 | import edu.uci.ics.jung.visualization.transform.shape.Intersector; | |
| 33 | ||
| 34 | ||
| 35 | ||
| 36 | /** | |
| 37 | * GraphZoomScrollPane is a Container for the Graph's VisualizationViewer | |
| 38 | * and includes custom horizontal and vertical scrollbars. | |
| 39 | * GraphZoomScrollPane listens for changes in the scale and | |
| 40 | * translation of the VisualizationViewer, and will update the | |
| 41 | * scrollbar positions and sizes accordingly. Changes in the | |
| 42 | * scrollbar positions will cause the corresponding change in | |
| 43 | * the translation component (offset) of the VisualizationViewer. | |
| 44 | * The scrollbars are modified so that they will allow panning | |
| 45 | * of the graph when the scale has been changed (e.g. zoomed-in | |
| 46 | * or zoomed-out). | |
| 47 | * | |
| 48 | * The lower-right corner of this component is available to | |
| 49 | * use as a small button or menu. | |
| 50 | * | |
| 51 | * samples.graph.GraphZoomScrollPaneDemo shows the use of this component. | |
| 52 | * | |
| 53 | * @author Tom Nelson - RABA Technologies | |
| 54 | * | |
| 55 | * | |
| 56 | */ | |
| 57 | 0 | public class GraphZoomScrollPane extends JPanel { |
| 58 | protected VisualizationViewer vv; | |
| 59 | protected JScrollBar horizontalScrollBar; | |
| 60 | protected JScrollBar verticalScrollBar; | |
| 61 | protected JComponent corner; | |
| 62 | 0 | protected boolean scrollBarsMayControlAdjusting = true; |
| 63 | protected JPanel south; | |
| 64 | ||
| 65 | /** | |
| 66 | * Create an instance of the GraphZoomScrollPane to contain the | |
| 67 | * VisualizationViewer | |
| 68 | * @param vv | |
| 69 | */ | |
| 70 | public GraphZoomScrollPane(VisualizationViewer vv) { | |
| 71 | 0 | super(new BorderLayout()); |
| 72 | 0 | this.vv = vv; |
| 73 | 0 | addComponentListener(new ResizeListener()); |
| 74 | 0 | Dimension d = vv.getGraphLayout().getCurrentSize(); |
| 75 | 0 | verticalScrollBar = new JScrollBar(JScrollBar.VERTICAL, 0, d.height, 0, d.height); |
| 76 | 0 | horizontalScrollBar = new JScrollBar(JScrollBar.HORIZONTAL, 0, d.width, 0, d.width); |
| 77 | 0 | verticalScrollBar.addAdjustmentListener(new VerticalAdjustmentListenerImpl()); |
| 78 | 0 | horizontalScrollBar.addAdjustmentListener(new HorizontalAdjustmentListenerImpl()); |
| 79 | 0 | verticalScrollBar.setUnitIncrement(20); |
| 80 | 0 | horizontalScrollBar.setUnitIncrement(20); |
| 81 | // respond to changes in the VisualizationViewer's transform | |
| 82 | // and set the scroll bar parameters appropriately | |
| 83 | 0 | vv.addChangeListener( |
| 84 | new ChangeListener(){ | |
| 85 | public void stateChanged(ChangeEvent evt) { | |
| 86 | VisualizationViewer vv = | |
| 87 | (VisualizationViewer)evt.getSource(); | |
| 88 | setScrollBars(vv); | |
| 89 | } | |
| 90 | }); | |
| 91 | 0 | add(vv); |
| 92 | 0 | add(verticalScrollBar, BorderLayout.EAST); |
| 93 | 0 | south = new JPanel(new BorderLayout()); |
| 94 | 0 | south.add(horizontalScrollBar); |
| 95 | 0 | setCorner(new JPanel()); |
| 96 | 0 | add(south, BorderLayout.SOUTH); |
| 97 | 0 | } |
| 98 | ||
| 99 | /** | |
| 100 | * listener for adjustment of the horizontal scroll bar. | |
| 101 | * Sets the translation of the VisualizationViewer | |
| 102 | */ | |
| 103 | class HorizontalAdjustmentListenerImpl implements AdjustmentListener { | |
| 104 | int previous = 0; | |
| 105 | public void adjustmentValueChanged(AdjustmentEvent e) { | |
| 106 | int hval = e.getValue(); | |
| 107 | float dh = previous - hval; | |
| 108 | previous = hval; | |
| 109 | if(dh != 0 && scrollBarsMayControlAdjusting) { | |
| 110 | // get the uniform scale of all transforms | |
| 111 | float layoutScale = (float) vv.getLayoutTransformer().getScale(); | |
| 112 | dh *= layoutScale; | |
| 113 | AffineTransform at = AffineTransform.getTranslateInstance(dh, 0); | |
| 114 | vv.getLayoutTransformer().preConcatenate(at); | |
| 115 | } | |
| 116 | } | |
| 117 | } | |
| 118 | ||
| 119 | /** | |
| 120 | * Listener for adjustment of the vertical scroll bar. | |
| 121 | * Sets the translation of the VisualizationViewer | |
| 122 | */ | |
| 123 | class VerticalAdjustmentListenerImpl implements AdjustmentListener { | |
| 124 | int previous = 0; | |
| 125 | public void adjustmentValueChanged(AdjustmentEvent e) { | |
| 126 | JScrollBar sb = (JScrollBar)e.getSource(); | |
| 127 | BoundedRangeModel m = sb.getModel(); | |
| 128 | int vval = m.getValue(); | |
| 129 | float dv = previous - vval; | |
| 130 | previous = vval; | |
| 131 | if(dv != 0 && scrollBarsMayControlAdjusting) { | |
| 132 | // get the uniform scale of all transforms | |
| 133 | float layoutScale = (float) vv.getLayoutTransformer().getScale(); | |
| 134 | dv *= layoutScale; | |
| 135 | AffineTransform at = AffineTransform.getTranslateInstance(0, dv); | |
| 136 | vv.getLayoutTransformer().preConcatenate(at); | |
| 137 | } | |
| 138 | } | |
| 139 | } | |
| 140 | ||
| 141 | /** | |
| 142 | * use the supplied vv characteristics to set the position and | |
| 143 | * dimensions of the scroll bars. Called in response to | |
| 144 | * a ChangeEvent from the VisualizationViewer | |
| 145 | * @param xform the transform of the VisualizationViewer | |
| 146 | */ | |
| 147 | private void setScrollBars(VisualizationViewer vv) { | |
| 148 | 0 | Dimension d = vv.getGraphLayout().getCurrentSize(); |
| 149 | 0 | Rectangle vvBounds = vv.getBounds(); |
| 150 | ||
| 151 | // a rectangle representing the layout | |
| 152 | 0 | Rectangle layoutRectangle = |
| 153 | new Rectangle(0,0,d.width,d.height); | |
| 154 | //-d.width/2, -d.height/2, 2*d.width, 2*d.height); | |
| 155 | ||
| 156 | 0 | Transformer viewTransformer = vv.getViewTransformer(); |
| 157 | 0 | Transformer layoutTransformer = vv.getLayoutTransformer(); |
| 158 | ||
| 159 | 0 | Point2D h0 = new Point2D.Double(vvBounds.getMinX(), vvBounds.getCenterY()); |
| 160 | 0 | Point2D h1 = new Point2D.Double(vvBounds.getMaxX(), vvBounds.getCenterY()); |
| 161 | 0 | Point2D v0 = new Point2D.Double(vvBounds.getCenterX(), vvBounds.getMinY()); |
| 162 | 0 | Point2D v1 = new Point2D.Double(vvBounds.getCenterX(), vvBounds.getMaxY()); |
| 163 | ||
| 164 | 0 | h0 = viewTransformer.inverseTransform(h0); |
| 165 | 0 | h0 = layoutTransformer.inverseTransform(h0); |
| 166 | 0 | h1 = viewTransformer.inverseTransform(h1); |
| 167 | 0 | h1 = layoutTransformer.inverseTransform(h1); |
| 168 | 0 | v0 = viewTransformer.inverseTransform(v0); |
| 169 | 0 | v0 = layoutTransformer.inverseTransform(v0); |
| 170 | 0 | v1 = viewTransformer.inverseTransform(v1); |
| 171 | 0 | v1 = layoutTransformer.inverseTransform(v1); |
| 172 | ||
| 173 | 0 | scrollBarsMayControlAdjusting = false; |
| 174 | 0 | setScrollBarValues(layoutRectangle, h0, h1, v0, v1); |
| 175 | 0 | scrollBarsMayControlAdjusting = true; |
| 176 | 0 | } |
| 177 | ||
| 178 | protected void setScrollBarValues(Rectangle rectangle, | |
| 179 | Point2D h0, Point2D h1, | |
| 180 | Point2D v0, Point2D v1) { | |
| 181 | 0 | boolean containsH0 = rectangle.contains(h0); |
| 182 | 0 | boolean containsH1 = rectangle.contains(h1); |
| 183 | 0 | boolean containsV0 = rectangle.contains(v0); |
| 184 | 0 | boolean containsV1 = rectangle.contains(v1); |
| 185 | ||
| 186 | // horizontal scrollbar: | |
| 187 | ||
| 188 | 0 | Intersector intersector = new Intersector(rectangle, new Line2D.Double(h0, h1)); |
| 189 | ||
| 190 | 0 | int min = 0; |
| 191 | int ext; | |
| 192 | 0 | int val = 0; |
| 193 | int max; | |
| 194 | ||
| 195 | 0 | Set points = intersector.getPoints(); |
| 196 | 0 | Point2D first = null; |
| 197 | 0 | Point2D second = null; |
| 198 | ||
| 199 | 0 | Point2D[] pointArray = (Point2D[])points.toArray(new Point2D[points.size()]); |
| 200 | 0 | if(pointArray.length > 1) { |
| 201 | 0 | first = pointArray[0]; |
| 202 | 0 | second = pointArray[1]; |
| 203 | 0 | } else if(pointArray.length > 0) { |
| 204 | 0 | first = second = pointArray[0]; |
| 205 | } | |
| 206 | ||
| 207 | 0 | if(first != null && second != null) { |
| 208 | // correct direction of intersect points | |
| 209 | 0 | if((h0.getX() - h1.getX()) * (first.getX() - second.getX()) < 0) { |
| 210 | // swap them | |
| 211 | 0 | Point2D temp = first; |
| 212 | 0 | first = second; |
| 213 | 0 | second = temp; |
| 214 | } | |
| 215 | ||
| 216 | 0 | if(containsH0 && containsH1) { |
| 217 | 0 | max = (int)first.distance(second); |
| 218 | 0 | val = (int)first.distance(h0); |
| 219 | 0 | ext = (int)h0.distance(h1); |
| 220 | ||
| 221 | 0 | } else if(containsH0) { |
| 222 | 0 | max = (int)first.distance(second); |
| 223 | 0 | val = (int)first.distance(h0); |
| 224 | 0 | ext = (int)h0.distance(second); |
| 225 | ||
| 226 | 0 | } else if(containsH1) { |
| 227 | 0 | max = (int) first.distance(second); |
| 228 | 0 | val = 0; |
| 229 | 0 | ext = (int) first.distance(h1); |
| 230 | ||
| 231 | } else { | |
| 232 | 0 | max = ext = rectangle.width; |
| 233 | 0 | val = min; |
| 234 | } | |
| 235 | 0 | horizontalScrollBar.setValues(val, ext+1, min, max); |
| 236 | } | |
| 237 | ||
| 238 | // vertical scroll bar | |
| 239 | 0 | min = val = 0; |
| 240 | ||
| 241 | 0 | intersector.intersectLine(new Line2D.Double(v0, v1)); |
| 242 | 0 | points = intersector.getPoints(); |
| 243 | ||
| 244 | 0 | pointArray = (Point2D[])points.toArray(new Point2D[points.size()]); |
| 245 | 0 | if(pointArray.length > 1) { |
| 246 | 0 | first = pointArray[0]; |
| 247 | 0 | second = pointArray[1]; |
| 248 | 0 | } else if(pointArray.length > 0) { |
| 249 | 0 | first = second = pointArray[0]; |
| 250 | } | |
| 251 | ||
| 252 | 0 | if(first != null && second != null) { |
| 253 | ||
| 254 | // arrange for direction | |
| 255 | 0 | if((v0.getY() - v1.getY()) * (first.getY() - second.getY()) < 0) { |
| 256 | // swap them | |
| 257 | 0 | Point2D temp = first; |
| 258 | 0 | first = second; |
| 259 | 0 | second = temp; |
| 260 | } | |
| 261 | ||
| 262 | 0 | if(containsV0 && containsV1) { |
| 263 | 0 | max = (int)first.distance(second); |
| 264 | 0 | val = (int)first.distance(v0); |
| 265 | 0 | ext = (int)v0.distance(v1); |
| 266 | ||
| 267 | 0 | } else if(containsV0) { |
| 268 | 0 | max = (int)first.distance(second); |
| 269 | 0 | val = (int)first.distance(v0); |
| 270 | 0 | ext = (int)v0.distance(second); |
| 271 | ||
| 272 | 0 | } else if(containsV1) { |
| 273 | 0 | max = (int) first.distance(second); |
| 274 | 0 | val = 0; |
| 275 | 0 | ext = (int) first.distance(v1); |
| 276 | ||
| 277 | } else { | |
| 278 | 0 | max = ext = rectangle.height; |
| 279 | 0 | val = min; |
| 280 | } | |
| 281 | 0 | verticalScrollBar.setValues(val, ext+1, min, max); |
| 282 | } | |
| 283 | 0 | } |
| 284 | ||
| 285 | /** | |
| 286 | * Listener to adjust the scroll bar parameters when the window | |
| 287 | * is resized | |
| 288 | */ | |
| 289 | protected class ResizeListener extends ComponentAdapter { | |
| 290 | ||
| 291 | public void componentHidden(ComponentEvent e) { | |
| 292 | } | |
| 293 | ||
| 294 | public void componentResized(ComponentEvent e) { | |
| 295 | setScrollBars(vv); | |
| 296 | } | |
| 297 | public void componentShown(ComponentEvent e) { | |
| 298 | } | |
| 299 | } | |
| 300 | ||
| 301 | /** | |
| 302 | * @return Returns the corner component. | |
| 303 | */ | |
| 304 | public JComponent getCorner() { | |
| 305 | 0 | return corner; |
| 306 | } | |
| 307 | ||
| 308 | /** | |
| 309 | * @param corner The cornerButton to set. | |
| 310 | */ | |
| 311 | public void setCorner(JComponent corner) { | |
| 312 | 0 | this.corner = corner; |
| 313 | 0 | corner.setPreferredSize(new Dimension(verticalScrollBar.getPreferredSize().width, |
| 314 | horizontalScrollBar.getPreferredSize().height)); | |
| 315 | 0 | south.add(this.corner, BorderLayout.EAST); |
| 316 | 0 | } |
| 317 | ||
| 318 | public JScrollBar getHorizontalScrollBar() { | |
| 319 | 0 | return horizontalScrollBar; |
| 320 | } | |
| 321 | ||
| 322 | public JScrollBar getVerticalScrollBar() { | |
| 323 | 0 | return verticalScrollBar; |
| 324 | } | |
| 325 | } |
|
this report was generated by version 1.0.5 of jcoverage. |
copyright © 2003, jcoverage ltd. all rights reserved. |