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