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 | float viewScale = (float) vv.getViewTransformer().getScale(); | |
113 | float scale = layoutScale*viewScale; | |
114 | dh *= scale; | |
115 | AffineTransform at = AffineTransform.getTranslateInstance(dh, 0); | |
116 | vv.getLayoutTransformer().preConcatenate(at); | |
117 | } | |
118 | } | |
119 | } | |
120 | ||
121 | /** | |
122 | * Listener for adjustment of the vertical scroll bar. | |
123 | * Sets the translation of the VisualizationViewer | |
124 | */ | |
125 | class VerticalAdjustmentListenerImpl implements AdjustmentListener { | |
126 | int previous = 0; | |
127 | public void adjustmentValueChanged(AdjustmentEvent e) { | |
128 | JScrollBar sb = (JScrollBar)e.getSource(); | |
129 | BoundedRangeModel m = sb.getModel(); | |
130 | int vval = m.getValue(); | |
131 | float dv = previous - vval; | |
132 | previous = vval; | |
133 | if(dv != 0 && scrollBarsMayControlAdjusting) { | |
134 | // get the uniform scale of all transforms | |
135 | float layoutScale = (float) vv.getLayoutTransformer().getScale(); | |
136 | float viewScale = (float) vv.getViewTransformer().getScale(); | |
137 | float scale = layoutScale*viewScale; | |
138 | dv *= scale; | |
139 | AffineTransform at = AffineTransform.getTranslateInstance(0, dv); | |
140 | vv.getLayoutTransformer().preConcatenate(at); | |
141 | } | |
142 | } | |
143 | } | |
144 | ||
145 | /** | |
146 | * use the supplied vv characteristics to set the position and | |
147 | * dimensions of the scroll bars. Called in response to | |
148 | * a ChangeEvent from the VisualizationViewer | |
149 | * @param xform the transform of the VisualizationViewer | |
150 | */ | |
151 | private void setScrollBars(VisualizationViewer vv) { | |
152 | 0 | Dimension d = vv.getGraphLayout().getCurrentSize(); |
153 | 0 | Rectangle vvBounds = vv.getBounds(); |
154 | ||
155 | // a rectangle representing the layout | |
156 | 0 | Rectangle layoutRectangle = |
157 | new Rectangle(-d.width/2, -d.height/2, 2*d.width, 2*d.height); | |
158 | ||
159 | 0 | Transformer viewTransformer = vv.getViewTransformer(); |
160 | 0 | Transformer layoutTransformer = vv.getLayoutTransformer(); |
161 | ||
162 | 0 | Point2D h0 = new Point2D.Double(vvBounds.getMinX(), vvBounds.getCenterY()); |
163 | 0 | Point2D h1 = new Point2D.Double(vvBounds.getMaxX(), vvBounds.getCenterY()); |
164 | 0 | Point2D v0 = new Point2D.Double(vvBounds.getCenterX(), vvBounds.getMinY()); |
165 | 0 | Point2D v1 = new Point2D.Double(vvBounds.getCenterX(), vvBounds.getMaxY()); |
166 | ||
167 | 0 | h0 = viewTransformer.inverseTransform(h0); |
168 | 0 | h0 = layoutTransformer.inverseTransform(h0); |
169 | 0 | h1 = viewTransformer.inverseTransform(h1); |
170 | 0 | h1 = layoutTransformer.inverseTransform(h1); |
171 | 0 | v0 = viewTransformer.inverseTransform(v0); |
172 | 0 | v0 = layoutTransformer.inverseTransform(v0); |
173 | 0 | v1 = viewTransformer.inverseTransform(v1); |
174 | 0 | v1 = layoutTransformer.inverseTransform(v1); |
175 | ||
176 | 0 | scrollBarsMayControlAdjusting = false; |
177 | 0 | setScrollBarValues(layoutRectangle, h0, h1, v0, v1); |
178 | 0 | scrollBarsMayControlAdjusting = true; |
179 | 0 | } |
180 | ||
181 | protected void setScrollBarValues(Rectangle rectangle, | |
182 | Point2D h0, Point2D h1, | |
183 | Point2D v0, Point2D v1) { | |
184 | 0 | boolean containsH0 = rectangle.contains(h0); |
185 | 0 | boolean containsH1 = rectangle.contains(h1); |
186 | 0 | boolean containsV0 = rectangle.contains(v0); |
187 | 0 | boolean containsV1 = rectangle.contains(v1); |
188 | ||
189 | // horizontal scrollbar: | |
190 | ||
191 | 0 | Intersector intersector = new Intersector(rectangle, new Line2D.Double(h0, h1)); |
192 | ||
193 | 0 | int min = 0; |
194 | int ext; | |
195 | 0 | int val = 0; |
196 | int max; | |
197 | ||
198 | 0 | Set points = intersector.getPoints(); |
199 | 0 | Point2D first = null; |
200 | 0 | Point2D second = null; |
201 | ||
202 | 0 | Point2D[] pointArray = (Point2D[])points.toArray(new Point2D[points.size()]); |
203 | 0 | if(pointArray.length > 1) { |
204 | 0 | first = pointArray[0]; |
205 | 0 | second = pointArray[1]; |
206 | 0 | } else if(pointArray.length > 0) { |
207 | 0 | first = second = pointArray[0]; |
208 | } | |
209 | ||
210 | 0 | if(first != null && second != null) { |
211 | // correct direction of intersect points | |
212 | 0 | if((h0.getX() - h1.getX()) * (first.getX() - second.getX()) < 0) { |
213 | // swap them | |
214 | 0 | Point2D temp = first; |
215 | 0 | first = second; |
216 | 0 | second = temp; |
217 | } | |
218 | ||
219 | 0 | if(containsH0 && containsH1) { |
220 | 0 | max = (int)first.distance(second); |
221 | 0 | val = (int)first.distance(h0); |
222 | 0 | ext = (int)h0.distance(h1); |
223 | ||
224 | 0 | } else if(containsH0) { |
225 | 0 | max = (int)first.distance(second); |
226 | 0 | val = (int)first.distance(h0); |
227 | 0 | ext = (int)h0.distance(second); |
228 | ||
229 | 0 | } else if(containsH1) { |
230 | 0 | max = (int) first.distance(second); |
231 | 0 | val = 0; |
232 | 0 | ext = (int) first.distance(h1); |
233 | ||
234 | } else { | |
235 | 0 | max = ext = rectangle.width; |
236 | 0 | val = min; |
237 | } | |
238 | 0 | horizontalScrollBar.setValues(val, ext+1, min, max); |
239 | } | |
240 | ||
241 | // vertical scroll bar | |
242 | 0 | min = val = 0; |
243 | ||
244 | 0 | intersector.intersectLine(new Line2D.Double(v0, v1)); |
245 | 0 | points = intersector.getPoints(); |
246 | ||
247 | 0 | pointArray = (Point2D[])points.toArray(new Point2D[points.size()]); |
248 | 0 | if(pointArray.length > 1) { |
249 | 0 | first = pointArray[0]; |
250 | 0 | second = pointArray[1]; |
251 | 0 | } else if(pointArray.length > 0) { |
252 | 0 | first = second = pointArray[0]; |
253 | } | |
254 | ||
255 | 0 | if(first != null && second != null) { |
256 | ||
257 | // arrange for direction | |
258 | 0 | if((v0.getY() - v1.getY()) * (first.getY() - second.getY()) < 0) { |
259 | // swap them | |
260 | 0 | Point2D temp = first; |
261 | 0 | first = second; |
262 | 0 | second = temp; |
263 | } | |
264 | ||
265 | 0 | if(containsV0 && containsV1) { |
266 | 0 | max = (int)first.distance(second); |
267 | 0 | val = (int)first.distance(v0); |
268 | 0 | ext = (int)v0.distance(v1); |
269 | ||
270 | 0 | } else if(containsV0) { |
271 | 0 | max = (int)first.distance(second); |
272 | 0 | val = (int)first.distance(v0); |
273 | 0 | ext = (int)v0.distance(second); |
274 | ||
275 | 0 | } else if(containsV1) { |
276 | 0 | max = (int) first.distance(second); |
277 | 0 | val = 0; |
278 | 0 | ext = (int) first.distance(v1); |
279 | ||
280 | } else { | |
281 | 0 | max = ext = rectangle.height; |
282 | 0 | val = min; |
283 | } | |
284 | 0 | verticalScrollBar.setValues(val, ext+1, min, max); |
285 | } | |
286 | 0 | } |
287 | ||
288 | /** | |
289 | * Listener to adjust the scroll bar parameters when the window | |
290 | * is resized | |
291 | */ | |
292 | protected class ResizeListener extends ComponentAdapter { | |
293 | ||
294 | public void componentHidden(ComponentEvent e) { | |
295 | } | |
296 | ||
297 | public void componentResized(ComponentEvent e) { | |
298 | setScrollBars(vv); | |
299 | } | |
300 | public void componentShown(ComponentEvent e) { | |
301 | } | |
302 | } | |
303 | ||
304 | /** | |
305 | * @return Returns the corner component. | |
306 | */ | |
307 | public JComponent getCorner() { | |
308 | 0 | return corner; |
309 | } | |
310 | ||
311 | /** | |
312 | * @param corner The cornerButton to set. | |
313 | */ | |
314 | public void setCorner(JComponent corner) { | |
315 | 0 | this.corner = corner; |
316 | 0 | corner.setPreferredSize(new Dimension(verticalScrollBar.getPreferredSize().width, |
317 | horizontalScrollBar.getPreferredSize().height)); | |
318 | 0 | south.add(this.corner, BorderLayout.EAST); |
319 | 0 | } |
320 | ||
321 | public JScrollBar getHorizontalScrollBar() { | |
322 | 0 | return horizontalScrollBar; |
323 | } | |
324 | ||
325 | public JScrollBar getVerticalScrollBar() { | |
326 | 0 | return verticalScrollBar; |
327 | } | |
328 | } |
this report was generated by version 1.0.5 of jcoverage. |
copyright © 2003, jcoverage ltd. all rights reserved. |