1
2
3
4
5
6
7
8
9
10 package edu.uci.ics.jung.visualization;
11
12 import java.awt.Color;
13 import java.awt.Dimension;
14 import java.awt.Graphics;
15 import java.awt.Graphics2D;
16 import java.awt.RenderingHints;
17 import java.awt.RenderingHints.Key;
18 import java.awt.event.ComponentAdapter;
19 import java.awt.event.ComponentEvent;
20 import java.awt.event.ItemEvent;
21 import java.awt.event.ItemListener;
22 import java.awt.geom.AffineTransform;
23 import java.awt.geom.Point2D;
24 import java.awt.image.BufferedImage;
25 import java.util.ArrayList;
26 import java.util.HashMap;
27 import java.util.List;
28 import java.util.Map;
29
30 import javax.swing.JPanel;
31 import javax.swing.event.ChangeEvent;
32 import javax.swing.event.ChangeListener;
33
34 import edu.uci.ics.jung.algorithms.layout.GraphElementAccessor;
35 import edu.uci.ics.jung.algorithms.layout.Layout;
36 import edu.uci.ics.jung.visualization.control.ScalingControl;
37 import edu.uci.ics.jung.visualization.decorators.PickableEdgePaintTransformer;
38 import edu.uci.ics.jung.visualization.decorators.PickableVertexPaintTransformer;
39 import edu.uci.ics.jung.visualization.picking.MultiPickedState;
40 import edu.uci.ics.jung.visualization.picking.PickedState;
41 import edu.uci.ics.jung.visualization.picking.ShapePickSupport;
42 import edu.uci.ics.jung.visualization.renderers.BasicRenderer;
43 import edu.uci.ics.jung.visualization.renderers.Renderer;
44 import edu.uci.ics.jung.visualization.transform.shape.GraphicsDecorator;
45 import edu.uci.ics.jung.visualization.util.Caching;
46 import edu.uci.ics.jung.visualization.util.ChangeEventSupport;
47 import edu.uci.ics.jung.visualization.util.DefaultChangeEventSupport;
48
49
50
51
52
53
54
55
56
57
58
59 @SuppressWarnings("serial")
60 public class BasicVisualizationServer<V, E> extends JPanel
61 implements ChangeListener, ChangeEventSupport, VisualizationServer<V, E>{
62
63 protected ChangeEventSupport changeSupport =
64 new DefaultChangeEventSupport(this);
65
66
67
68
69 protected VisualizationModel<V,E> model;
70
71
72
73
74 protected Renderer<V,E> renderer = new BasicRenderer<V,E>();
75
76
77
78
79
80 protected Map<Key, Object> renderingHints = new HashMap<Key, Object>();
81
82
83
84
85
86 protected PickedState<V> pickedVertexState;
87
88
89
90
91
92 protected PickedState<E> pickedEdgeState;
93
94
95
96
97
98 protected ItemListener pickEventListener;
99
100
101
102
103
104 protected BufferedImage offscreen;
105
106
107
108
109
110 protected Graphics2D offscreenG2d;
111
112
113
114
115
116 protected boolean doubleBuffered;
117
118
119
120
121
122 protected List<Paintable> preRenderers = new ArrayList<Paintable>();
123
124
125
126
127
128 protected List<Paintable> postRenderers = new ArrayList<Paintable>();
129
130 protected RenderContext<V,E> renderContext;
131
132
133
134
135
136
137 public BasicVisualizationServer(Layout<V,E> layout) {
138 this(new DefaultVisualizationModel<V,E>(layout));
139 }
140
141
142
143
144
145
146
147 public BasicVisualizationServer(Layout<V,E> layout, Dimension preferredSize) {
148 this(new DefaultVisualizationModel<V,E>(layout, preferredSize), preferredSize);
149 }
150
151
152
153
154
155
156 public BasicVisualizationServer(VisualizationModel<V,E> model) {
157 this(model, new Dimension(600,600));
158 }
159
160
161
162
163
164
165
166 public BasicVisualizationServer(VisualizationModel<V,E> model,
167 Dimension preferredSize) {
168 this.model = model;
169 renderContext = new PluggableRenderContext<V,E>(model.getGraphLayout().getGraph());
170 model.addChangeListener(this);
171 setDoubleBuffered(false);
172 this.addComponentListener(new VisualizationListener(this));
173
174 setPickSupport(new ShapePickSupport<V,E>(this));
175 setPickedVertexState(new MultiPickedState<V>());
176 setPickedEdgeState(new MultiPickedState<E>());
177
178 renderContext.setEdgeDrawPaintTransformer(new PickableEdgePaintTransformer<E>(getPickedEdgeState(), Color.black, Color.cyan));
179 renderContext.setVertexFillPaintTransformer(new PickableVertexPaintTransformer<V>(getPickedVertexState(),
180 Color.red, Color.yellow));
181
182 setPreferredSize(preferredSize);
183 renderingHints.put(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
184
185 renderContext.getMultiLayerTransformer().addChangeListener(this);
186 }
187
188 @Override
189 public void setDoubleBuffered(boolean doubleBuffered) {
190 this.doubleBuffered = doubleBuffered;
191 }
192
193 @Override
194 public boolean isDoubleBuffered() {
195 return doubleBuffered;
196 }
197
198
199
200
201
202
203 @Override
204 public Dimension getSize() {
205 Dimension d = super.getSize();
206 if(d.width <= 0 || d.height <= 0) {
207 d = getPreferredSize();
208 }
209 return d;
210 }
211
212
213
214
215
216
217 protected void checkOffscreenImage(Dimension d) {
218 if(doubleBuffered) {
219 if(offscreen == null || offscreen.getWidth() != d.width || offscreen.getHeight() != d.height) {
220 offscreen = new BufferedImage(d.width, d.height, BufferedImage.TYPE_INT_ARGB);
221 offscreenG2d = offscreen.createGraphics();
222 }
223 }
224 }
225
226 public VisualizationModel<V,E> getModel() {
227 return model;
228 }
229
230 public void setModel(VisualizationModel<V,E> model) {
231 this.model = model;
232 }
233
234 public void stateChanged(ChangeEvent e) {
235 repaint();
236 fireStateChanged();
237 }
238
239 public void setRenderer(Renderer<V,E> r) {
240 this.renderer = r;
241 repaint();
242 }
243
244 public Renderer<V,E> getRenderer() {
245 return renderer;
246 }
247
248 public void setGraphLayout(Layout<V,E> layout) {
249 Dimension viewSize = getPreferredSize();
250 if(this.isShowing()) {
251 viewSize = getSize();
252 }
253 model.setGraphLayout(layout, viewSize);
254 }
255
256 public void scaleToLayout(ScalingControl scaler) {
257 Dimension vd = getPreferredSize();
258 if(this.isShowing()) {
259 vd = getSize();
260 }
261 Dimension ld = getGraphLayout().getSize();
262 if(vd.equals(ld) == false) {
263 scaler.scale(this, (float)(vd.getWidth()/ld.getWidth()), new Point2D.Double());
264 }
265 }
266
267 public Layout<V,E> getGraphLayout() {
268 return model.getGraphLayout();
269 }
270
271 @Override
272 public void setVisible(boolean aFlag) {
273 super.setVisible(aFlag);
274 if(aFlag == true) {
275 Dimension d = this.getSize();
276 if(d.width <= 0 || d.height <= 0) {
277 d = this.getPreferredSize();
278 }
279 model.getGraphLayout().setSize(d);
280 }
281 }
282
283 public Map<Key, Object> getRenderingHints() {
284 return renderingHints;
285 }
286
287 public void setRenderingHints(Map<Key, Object> renderingHints) {
288 this.renderingHints = renderingHints;
289 }
290
291 @Override
292 protected void paintComponent(Graphics g) {
293 super.paintComponent(g);
294
295 Graphics2D g2d = (Graphics2D)g;
296 if(doubleBuffered) {
297 checkOffscreenImage(getSize());
298 renderGraph(offscreenG2d);
299 g2d.drawImage(offscreen, null, 0, 0);
300 } else {
301 renderGraph(g2d);
302 }
303 }
304
305 protected void renderGraph(Graphics2D g2d) {
306 if(renderContext.getGraphicsContext() == null) {
307 renderContext.setGraphicsContext(new GraphicsDecorator(g2d));
308 } else {
309 renderContext.getGraphicsContext().setDelegate(g2d);
310 }
311 renderContext.setScreenDevice(this);
312 Layout<V,E> layout = model.getGraphLayout();
313
314 g2d.setRenderingHints(renderingHints);
315
316
317 Dimension d = getSize();
318
319
320 g2d.setColor(getBackground());
321 g2d.fillRect(0,0,d.width,d.height);
322
323 AffineTransform oldXform = g2d.getTransform();
324 AffineTransform newXform = new AffineTransform(oldXform);
325 newXform.concatenate(
326 renderContext.getMultiLayerTransformer().getTransformer(Layer.VIEW).getTransform());
327
328 g2d.setTransform(newXform);
329
330
331 for(Paintable paintable : preRenderers) {
332
333 if(paintable.useTransform()) {
334 paintable.paint(g2d);
335 } else {
336 g2d.setTransform(oldXform);
337 paintable.paint(g2d);
338 g2d.setTransform(newXform);
339 }
340 }
341
342 if(layout instanceof Caching) {
343 ((Caching)layout).clear();
344 }
345
346 renderer.render(renderContext, layout);
347
348
349 for(Paintable paintable : postRenderers) {
350
351 if(paintable.useTransform()) {
352 paintable.paint(g2d);
353 } else {
354 g2d.setTransform(oldXform);
355 paintable.paint(g2d);
356 g2d.setTransform(newXform);
357 }
358 }
359 g2d.setTransform(oldXform);
360 }
361
362
363
364
365
366
367
368
369
370
371 protected class VisualizationListener extends ComponentAdapter {
372 protected BasicVisualizationServer<V,E> vv;
373 public VisualizationListener(BasicVisualizationServer<V,E> vv) {
374 this.vv = vv;
375 }
376
377
378
379
380
381 @Override
382 public void componentResized(ComponentEvent e) {
383 Dimension d = vv.getSize();
384 if(d.width <= 0 || d.height <= 0) return;
385 checkOffscreenImage(d);
386 repaint();
387 }
388 }
389
390 public void addPreRenderPaintable(Paintable paintable) {
391 if(preRenderers == null) {
392 preRenderers = new ArrayList<Paintable>();
393 }
394 preRenderers.add(paintable);
395 }
396
397 public void prependPreRenderPaintable(Paintable paintable) {
398 if(preRenderers == null) {
399 preRenderers = new ArrayList<Paintable>();
400 }
401 preRenderers.add(0,paintable);
402 }
403
404 public void removePreRenderPaintable(Paintable paintable) {
405 if(preRenderers != null) {
406 preRenderers.remove(paintable);
407 }
408 }
409
410 public void addPostRenderPaintable(Paintable paintable) {
411 if(postRenderers == null) {
412 postRenderers = new ArrayList<Paintable>();
413 }
414 postRenderers.add(paintable);
415 }
416
417 public void prependPostRenderPaintable(Paintable paintable) {
418 if(postRenderers == null) {
419 postRenderers = new ArrayList<Paintable>();
420 }
421 postRenderers.add(0,paintable);
422 }
423
424 public void removePostRenderPaintable(Paintable paintable) {
425 if(postRenderers != null) {
426 postRenderers.remove(paintable);
427 }
428 }
429
430 public void addChangeListener(ChangeListener l) {
431 changeSupport.addChangeListener(l);
432 }
433
434 public void removeChangeListener(ChangeListener l) {
435 changeSupport.removeChangeListener(l);
436 }
437
438 public ChangeListener[] getChangeListeners() {
439 return changeSupport.getChangeListeners();
440 }
441
442 public void fireStateChanged() {
443 changeSupport.fireStateChanged();
444 }
445
446 public PickedState<V> getPickedVertexState() {
447 return pickedVertexState;
448 }
449
450 public PickedState<E> getPickedEdgeState() {
451 return pickedEdgeState;
452 }
453
454 public void setPickedVertexState(PickedState<V> pickedVertexState) {
455 if(pickEventListener != null && this.pickedVertexState != null) {
456 this.pickedVertexState.removeItemListener(pickEventListener);
457 }
458 this.pickedVertexState = pickedVertexState;
459 this.renderContext.setPickedVertexState(pickedVertexState);
460 if(pickEventListener == null) {
461 pickEventListener = new ItemListener() {
462
463 public void itemStateChanged(ItemEvent e) {
464 repaint();
465 }
466 };
467 }
468 pickedVertexState.addItemListener(pickEventListener);
469 }
470
471 public void setPickedEdgeState(PickedState<E> pickedEdgeState) {
472 if(pickEventListener != null && this.pickedEdgeState != null) {
473 this.pickedEdgeState.removeItemListener(pickEventListener);
474 }
475 this.pickedEdgeState = pickedEdgeState;
476 this.renderContext.setPickedEdgeState(pickedEdgeState);
477 if(pickEventListener == null) {
478 pickEventListener = new ItemListener() {
479
480 public void itemStateChanged(ItemEvent e) {
481 repaint();
482 }
483 };
484 }
485 pickedEdgeState.addItemListener(pickEventListener);
486 }
487
488 public GraphElementAccessor<V,E> getPickSupport() {
489 return renderContext.getPickSupport();
490 }
491
492 public void setPickSupport(GraphElementAccessor<V,E> pickSupport) {
493 renderContext.setPickSupport(pickSupport);
494 }
495
496 public Point2D getCenter() {
497 Dimension d = getSize();
498 return new Point2D.Float(d.width/2, d.height/2);
499 }
500
501 public RenderContext<V,E> getRenderContext() {
502 return renderContext;
503 }
504
505 public void setRenderContext(RenderContext<V,E> renderContext) {
506 this.renderContext = renderContext;
507 }
508 }