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 = new PluggableRenderContext<V,E>();
131
132
133
134
135
136
137
138 public BasicVisualizationServer(Layout<V,E> layout) {
139 this(new DefaultVisualizationModel<V,E>(layout));
140 }
141
142
143
144
145
146
147
148
149 public BasicVisualizationServer(Layout<V,E> layout, Dimension preferredSize) {
150 this(new DefaultVisualizationModel<V,E>(layout, preferredSize), preferredSize);
151 }
152
153
154
155
156
157
158
159 public BasicVisualizationServer(VisualizationModel<V,E> model) {
160 this(model, new Dimension(600,600));
161 }
162
163
164
165
166
167
168
169 @SuppressWarnings("unchecked")
170 public BasicVisualizationServer(VisualizationModel<V,E> model,
171 Dimension preferredSize) {
172 this.model = model;
173
174 model.addChangeListener(this);
175 setDoubleBuffered(false);
176 this.addComponentListener(new VisualizationListener(this));
177
178 setPickSupport(new ShapePickSupport<V,E>(this));
179 setPickedVertexState(new MultiPickedState<V>());
180 setPickedEdgeState(new MultiPickedState<E>());
181
182 renderContext.setEdgeDrawPaintTransformer(new PickableEdgePaintTransformer<E>(getPickedEdgeState(), Color.black, Color.cyan));
183 renderContext.setVertexFillPaintTransformer(new PickableVertexPaintTransformer<V>(getPickedVertexState(),
184 Color.red, Color.yellow));
185
186 setPreferredSize(preferredSize);
187 renderingHints.put(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
188
189 renderContext.getMultiLayerTransformer().addChangeListener(this);
190 }
191
192 @Override
193 public void setDoubleBuffered(boolean doubleBuffered) {
194 this.doubleBuffered = doubleBuffered;
195 }
196
197 @Override
198 public boolean isDoubleBuffered() {
199 return doubleBuffered;
200 }
201
202
203
204
205
206
207 @Override
208 public Dimension getSize() {
209 Dimension d = super.getSize();
210 if(d.width <= 0 || d.height <= 0) {
211 d = getPreferredSize();
212 }
213 return d;
214 }
215
216
217
218
219
220
221 protected void checkOffscreenImage(Dimension d) {
222 if(doubleBuffered) {
223 if(offscreen == null || offscreen.getWidth() != d.width || offscreen.getHeight() != d.height) {
224 offscreen = new BufferedImage(d.width, d.height, BufferedImage.TYPE_INT_ARGB);
225 offscreenG2d = offscreen.createGraphics();
226 }
227 }
228 }
229
230
231
232
233 public VisualizationModel<V,E> getModel() {
234 return model;
235 }
236
237
238
239 public void setModel(VisualizationModel<V,E> model) {
240 this.model = model;
241 }
242
243
244
245 public void stateChanged(ChangeEvent e) {
246 repaint();
247 fireStateChanged();
248 }
249
250
251
252
253 public void setRenderer(Renderer<V,E> r) {
254 this.renderer = r;
255 repaint();
256 }
257
258
259
260
261 public Renderer<V,E> getRenderer() {
262 return renderer;
263 }
264
265
266
267
268 public void setGraphLayout(Layout<V,E> layout) {
269 Dimension viewSize = getPreferredSize();
270 if(this.isShowing()) {
271 viewSize = getSize();
272 }
273 model.setGraphLayout(layout, viewSize);
274 }
275
276 public void scaleToLayout(ScalingControl scaler) {
277 Dimension vd = getPreferredSize();
278 if(this.isShowing()) {
279 vd = getSize();
280 }
281 Dimension ld = getGraphLayout().getSize();
282 if(vd.equals(ld) == false) {
283 scaler.scale(this, (float)(vd.getWidth()/ld.getWidth()), new Point2D.Double());
284 }
285 }
286
287 public Layout<V,E> getGraphLayout() {
288 return model.getGraphLayout();
289 }
290
291 @Override
292 public void setVisible(boolean aFlag) {
293 super.setVisible(aFlag);
294 if(aFlag == true) {
295 Dimension d = this.getSize();
296 if(d.width <= 0 || d.height <= 0) {
297 d = this.getPreferredSize();
298 }
299 model.getGraphLayout().setSize(d);
300 }
301 }
302
303 public Map<Key, Object> getRenderingHints() {
304 return renderingHints;
305 }
306
307 public void setRenderingHints(Map<Key, Object> renderingHints) {
308 this.renderingHints = renderingHints;
309 }
310
311 @Override
312 protected void paintComponent(Graphics g) {
313 super.paintComponent(g);
314
315 Graphics2D g2d = (Graphics2D)g;
316 if(doubleBuffered) {
317 checkOffscreenImage(getSize());
318 renderGraph(offscreenG2d);
319 g2d.drawImage(offscreen, null, 0, 0);
320 } else {
321 renderGraph(g2d);
322 }
323 }
324
325 protected void renderGraph(Graphics2D g2d) {
326 if(renderContext.getGraphicsContext() == null) {
327 renderContext.setGraphicsContext(new GraphicsDecorator(g2d));
328 } else {
329 renderContext.getGraphicsContext().setDelegate(g2d);
330 }
331 renderContext.setScreenDevice(this);
332 Layout<V,E> layout = model.getGraphLayout();
333
334 g2d.setRenderingHints(renderingHints);
335
336
337 Dimension d = getSize();
338
339
340 g2d.setColor(getBackground());
341 g2d.fillRect(0,0,d.width,d.height);
342
343 AffineTransform oldXform = g2d.getTransform();
344 AffineTransform newXform = new AffineTransform(oldXform);
345 newXform.concatenate(
346 renderContext.getMultiLayerTransformer().getTransformer(Layer.VIEW).getTransform());
347
348
349 g2d.setTransform(newXform);
350
351
352 for(Paintable paintable : preRenderers) {
353
354 if(paintable.useTransform()) {
355 paintable.paint(g2d);
356 } else {
357 g2d.setTransform(oldXform);
358 paintable.paint(g2d);
359 g2d.setTransform(newXform);
360 }
361 }
362
363 if(layout instanceof Caching) {
364 ((Caching)layout).clear();
365 }
366
367 renderer.render(renderContext, layout);
368
369
370 for(Paintable paintable : postRenderers) {
371
372 if(paintable.useTransform()) {
373 paintable.paint(g2d);
374 } else {
375 g2d.setTransform(oldXform);
376 paintable.paint(g2d);
377 g2d.setTransform(newXform);
378 }
379 }
380 g2d.setTransform(oldXform);
381 }
382
383
384
385
386
387
388
389
390
391
392 protected class VisualizationListener extends ComponentAdapter {
393 protected BasicVisualizationServer<V,E> vv;
394 public VisualizationListener(BasicVisualizationServer<V,E> vv) {
395 this.vv = vv;
396 }
397
398
399
400
401
402 @Override
403 public void componentResized(ComponentEvent e) {
404 Dimension d = vv.getSize();
405 if(d.width <= 0 || d.height <= 0) return;
406 checkOffscreenImage(d);
407 repaint();
408 }
409 }
410
411 public void addPreRenderPaintable(Paintable paintable) {
412 if(preRenderers == null) {
413 preRenderers = new ArrayList<Paintable>();
414 }
415 preRenderers.add(paintable);
416 }
417
418 public void prependPreRenderPaintable(Paintable paintable) {
419 if(preRenderers == null) {
420 preRenderers = new ArrayList<Paintable>();
421 }
422 preRenderers.add(0,paintable);
423 }
424
425 public void removePreRenderPaintable(Paintable paintable) {
426 if(preRenderers != null) {
427 preRenderers.remove(paintable);
428 }
429 }
430
431 public void addPostRenderPaintable(Paintable paintable) {
432 if(postRenderers == null) {
433 postRenderers = new ArrayList<Paintable>();
434 }
435 postRenderers.add(paintable);
436 }
437
438 public void prependPostRenderPaintable(Paintable paintable) {
439 if(postRenderers == null) {
440 postRenderers = new ArrayList<Paintable>();
441 }
442 postRenderers.add(0,paintable);
443 }
444
445 public void removePostRenderPaintable(Paintable paintable) {
446 if(postRenderers != null) {
447 postRenderers.remove(paintable);
448 }
449 }
450
451 public void addChangeListener(ChangeListener l) {
452 changeSupport.addChangeListener(l);
453 }
454
455 public void removeChangeListener(ChangeListener l) {
456 changeSupport.removeChangeListener(l);
457 }
458
459 public ChangeListener[] getChangeListeners() {
460 return changeSupport.getChangeListeners();
461 }
462
463 public void fireStateChanged() {
464 changeSupport.fireStateChanged();
465 }
466
467 public PickedState<V> getPickedVertexState() {
468 return pickedVertexState;
469 }
470
471 public PickedState<E> getPickedEdgeState() {
472 return pickedEdgeState;
473 }
474
475 public void setPickedVertexState(PickedState<V> pickedVertexState) {
476 if(pickEventListener != null && this.pickedVertexState != null) {
477 this.pickedVertexState.removeItemListener(pickEventListener);
478 }
479 this.pickedVertexState = pickedVertexState;
480 this.renderContext.setPickedVertexState(pickedVertexState);
481 if(pickEventListener == null) {
482 pickEventListener = new ItemListener() {
483
484 public void itemStateChanged(ItemEvent e) {
485 repaint();
486 }
487 };
488 }
489 pickedVertexState.addItemListener(pickEventListener);
490 }
491
492
493
494
495 public void setPickedEdgeState(PickedState<E> pickedEdgeState) {
496 if(pickEventListener != null && this.pickedEdgeState != null) {
497 this.pickedEdgeState.removeItemListener(pickEventListener);
498 }
499 this.pickedEdgeState = pickedEdgeState;
500 this.renderContext.setPickedEdgeState(pickedEdgeState);
501 if(pickEventListener == null) {
502 pickEventListener = new ItemListener() {
503
504 public void itemStateChanged(ItemEvent e) {
505 repaint();
506 }
507 };
508 }
509 pickedEdgeState.addItemListener(pickEventListener);
510 }
511
512
513
514
515 public GraphElementAccessor<V,E> getPickSupport() {
516 return renderContext.getPickSupport();
517 }
518
519
520
521 public void setPickSupport(GraphElementAccessor<V,E> pickSupport) {
522 renderContext.setPickSupport(pickSupport);
523 }
524
525
526
527
528 public Point2D getCenter() {
529 Dimension d = getSize();
530 return new Point2D.Float(d.width/2, d.height/2);
531 }
532
533
534
535
536 public RenderContext<V,E> getRenderContext() {
537 return renderContext;
538 }
539
540
541
542
543 public void setRenderContext(RenderContext<V,E> renderContext) {
544 this.renderContext = renderContext;
545 }
546 }