1
2
3
4
5
6
7
8
9
10
11 package edu.uci.ics.jung.samples;
12
13 import java.awt.BasicStroke;
14 import java.awt.BorderLayout;
15 import java.awt.Color;
16 import java.awt.Component;
17 import java.awt.Dimension;
18 import java.awt.Font;
19 import java.awt.GradientPaint;
20 import java.awt.GridLayout;
21 import java.awt.Paint;
22 import java.awt.Shape;
23 import java.awt.Stroke;
24 import java.awt.event.ActionEvent;
25 import java.awt.event.ActionListener;
26 import java.awt.event.ItemEvent;
27 import java.awt.event.ItemListener;
28 import java.awt.event.MouseEvent;
29 import java.awt.event.MouseListener;
30 import java.awt.geom.Point2D;
31 import java.util.Collection;
32 import java.util.HashMap;
33 import java.util.HashSet;
34 import java.util.Map;
35 import java.util.Set;
36
37 import javax.swing.AbstractAction;
38 import javax.swing.AbstractButton;
39 import javax.swing.BorderFactory;
40 import javax.swing.Box;
41 import javax.swing.ButtonGroup;
42 import javax.swing.JApplet;
43 import javax.swing.JButton;
44 import javax.swing.JCheckBox;
45 import javax.swing.JComboBox;
46 import javax.swing.JFrame;
47 import javax.swing.JPanel;
48 import javax.swing.JPopupMenu;
49 import javax.swing.JRadioButton;
50
51 import com.google.common.base.Function;
52 import com.google.common.base.Functions;
53 import com.google.common.base.Predicate;
54 import com.google.common.base.Supplier;
55
56 import edu.uci.ics.jung.algorithms.generators.random.MixedRandomGraphGenerator;
57 import edu.uci.ics.jung.algorithms.layout.FRLayout;
58 import edu.uci.ics.jung.algorithms.layout.GraphElementAccessor;
59 import edu.uci.ics.jung.algorithms.layout.Layout;
60 import edu.uci.ics.jung.algorithms.scoring.VoltageScorer;
61 import edu.uci.ics.jung.algorithms.scoring.util.VertexScoreTransformer;
62 import edu.uci.ics.jung.algorithms.util.SelfLoopEdgePredicate;
63 import edu.uci.ics.jung.graph.Graph;
64 import edu.uci.ics.jung.graph.SparseMultigraph;
65 import edu.uci.ics.jung.graph.util.Context;
66 import edu.uci.ics.jung.graph.util.EdgeType;
67 import edu.uci.ics.jung.visualization.GraphZoomScrollPane;
68 import edu.uci.ics.jung.visualization.RenderContext;
69 import edu.uci.ics.jung.visualization.VisualizationViewer;
70 import edu.uci.ics.jung.visualization.control.AbstractPopupGraphMousePlugin;
71 import edu.uci.ics.jung.visualization.control.CrossoverScalingControl;
72 import edu.uci.ics.jung.visualization.control.DefaultModalGraphMouse;
73 import edu.uci.ics.jung.visualization.control.ScalingControl;
74 import edu.uci.ics.jung.visualization.decorators.AbstractVertexShapeTransformer;
75 import edu.uci.ics.jung.visualization.decorators.EdgeShape;
76 import edu.uci.ics.jung.visualization.decorators.GradientEdgePaintTransformer;
77 import edu.uci.ics.jung.visualization.decorators.NumberFormattingTransformer;
78 import edu.uci.ics.jung.visualization.decorators.PickableEdgePaintTransformer;
79 import edu.uci.ics.jung.visualization.picking.PickedInfo;
80 import edu.uci.ics.jung.visualization.picking.PickedState;
81 import edu.uci.ics.jung.visualization.renderers.BasicEdgeArrowRenderingSupport;
82 import edu.uci.ics.jung.visualization.renderers.CachingEdgeRenderer;
83 import edu.uci.ics.jung.visualization.renderers.CachingVertexRenderer;
84 import edu.uci.ics.jung.visualization.renderers.CenterEdgeArrowRenderingSupport;
85 import edu.uci.ics.jung.visualization.renderers.Renderer;
86 import edu.uci.ics.jung.visualization.renderers.Renderer.VertexLabel.Position;
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176 @SuppressWarnings("serial")
177 public class PluggableRendererDemo extends JApplet implements ActionListener
178 {
179 protected JCheckBox v_color;
180 protected JCheckBox e_color;
181 protected JCheckBox v_stroke;
182 protected JCheckBox e_uarrow_pred;
183 protected JCheckBox e_darrow_pred;
184 protected JCheckBox e_arrow_centered;
185 protected JCheckBox v_shape;
186 protected JCheckBox v_size;
187 protected JCheckBox v_aspect;
188 protected JCheckBox v_labels;
189 protected JRadioButton e_line;
190 protected JRadioButton e_bent;
191 protected JRadioButton e_wedge;
192 protected JRadioButton e_quad;
193 protected JRadioButton e_ortho;
194 protected JRadioButton e_cubic;
195 protected JCheckBox e_labels;
196 protected JCheckBox font;
197 protected JCheckBox e_show_d;
198 protected JCheckBox e_show_u;
199 protected JCheckBox v_small;
200 protected JCheckBox zoom_at_mouse;
201 protected JCheckBox fill_edges;
202
203 protected JRadioButton no_gradient;
204 protected JRadioButton gradient_relative;
205
206 protected static final int GRADIENT_NONE = 0;
207 protected static final int GRADIENT_RELATIVE = 1;
208 protected static int gradient_level = GRADIENT_NONE;
209
210 protected SeedFillColor<Integer> seedFillColor;
211 protected SeedDrawColor<Integer> seedDrawColor;
212 protected EdgeWeightStrokeFunction<Number> ewcs;
213 protected VertexStrokeHighlight<Integer,Number> vsh;
214 protected Function<? super Integer,String> vs;
215 protected Function<? super Integer,String> vs_none;
216 protected Function<? super Number,String> es;
217 protected Function<? super Number,String> es_none;
218 protected VertexFontTransformer<Integer> vff;
219 protected EdgeFontTransformer<Number> eff;
220 protected VertexShapeSizeAspect<Integer,Number> vssa;
221 protected DirectionDisplayPredicate<Integer,Number> show_edge;
222 protected DirectionDisplayPredicate<Integer,Number> show_arrow;
223 protected VertexDisplayPredicate<Integer,Number> show_vertex;
224 protected Predicate<Context<Graph<Integer,Number>,Number>> self_loop;
225 protected GradientPickedEdgePaintFunction<Integer,Number> edgeDrawPaint;
226 protected GradientPickedEdgePaintFunction<Integer,Number> edgeFillPaint;
227 protected final static Object VOLTAGE_KEY = "voltages";
228 protected final static Object TRANSPARENCY = "transparency";
229
230 protected Map<Number,Number> edge_weight = new HashMap<Number,Number>();
231 protected Function<Integer, Double> voltages;
232 protected Map<Integer,Number> transparency = new HashMap<Integer,Number>();
233
234 protected VisualizationViewer<Integer,Number> vv;
235 protected DefaultModalGraphMouse<Integer, Number> gm;
236 protected Set<Integer> seedVertices = new HashSet<Integer>();
237
238 private Graph<Integer, Number> graph;
239
240 public void start()
241 {
242 getContentPane().add( startFunction() );
243 }
244
245 public static void main(String[] s )
246 {
247 JFrame jf = new JFrame();
248 jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
249 JPanel jp = new PluggableRendererDemo().startFunction();
250 jf.getContentPane().add(jp);
251 jf.pack();
252 jf.setVisible(true);
253 }
254
255
256 public JPanel startFunction() {
257 this.graph = buildGraph();
258
259 Layout<Integer,Number> layout = new FRLayout<Integer,Number>(graph);
260 vv = new VisualizationViewer<Integer,Number>(layout);
261
262 vv.getRenderer().setVertexRenderer(new CachingVertexRenderer<Integer,Number>(vv));
263 vv.getRenderer().setEdgeRenderer(new CachingEdgeRenderer<Integer,Number>(vv));
264
265 PickedState<Integer> picked_state = vv.getPickedVertexState();
266
267 self_loop = new SelfLoopEdgePredicate<Integer,Number>();
268
269 seedFillColor = new SeedFillColor<Integer>(picked_state);
270 seedDrawColor = new SeedDrawColor<Integer>();
271 ewcs =
272 new EdgeWeightStrokeFunction<Number>(edge_weight);
273 vsh = new VertexStrokeHighlight<Integer,Number>(graph, picked_state);
274 vff = new VertexFontTransformer<Integer>();
275 eff = new EdgeFontTransformer<Number>();
276 vs_none = Functions.constant(null);
277 es_none = Functions.constant(null);
278 vssa = new VertexShapeSizeAspect<Integer,Number>(graph, voltages);
279 show_edge = new DirectionDisplayPredicate<Integer,Number>(true, true);
280 show_arrow = new DirectionDisplayPredicate<Integer,Number>(true, false);
281 show_vertex = new VertexDisplayPredicate<Integer,Number>(false);
282
283
284 edgeDrawPaint =
285 new GradientPickedEdgePaintFunction<Integer,Number>(
286 new PickableEdgePaintTransformer<Number>(
287 vv.getPickedEdgeState(),Color.black,Color.cyan), vv);
288 edgeFillPaint =
289 new GradientPickedEdgePaintFunction<Integer,Number>(
290 new PickableEdgePaintTransformer<Number>(
291 vv.getPickedEdgeState(),Color.black,Color.cyan), vv);
292
293 vv.getRenderContext().setVertexFillPaintTransformer(seedFillColor);
294 vv.getRenderContext().setVertexDrawPaintTransformer(seedDrawColor);
295 vv.getRenderContext().setVertexStrokeTransformer(vsh);
296 vv.getRenderContext().setVertexLabelTransformer(vs_none);
297 vv.getRenderContext().setVertexFontTransformer(vff);
298 vv.getRenderContext().setVertexShapeTransformer(vssa);
299 vv.getRenderContext().setVertexIncludePredicate(show_vertex);
300
301 vv.getRenderContext().setEdgeDrawPaintTransformer( edgeDrawPaint );
302 vv.getRenderContext().setEdgeLabelTransformer(es_none);
303 vv.getRenderContext().setEdgeFontTransformer(eff);
304 vv.getRenderContext().setEdgeStrokeTransformer(ewcs);
305 vv.getRenderContext().setEdgeIncludePredicate(show_edge);
306 vv.getRenderContext().setEdgeShapeTransformer(EdgeShape.line(graph));
307 vv.getRenderContext().setEdgeArrowPredicate(show_arrow);
308
309 vv.getRenderContext().setArrowFillPaintTransformer(Functions.<Paint>constant(Color.lightGray));
310 vv.getRenderContext().setArrowDrawPaintTransformer(Functions.<Paint>constant(Color.black));
311 JPanel jp = new JPanel();
312 jp.setLayout(new BorderLayout());
313
314 vv.setBackground(Color.white);
315 GraphZoomScrollPane scrollPane = new GraphZoomScrollPane(vv);
316 jp.add(scrollPane);
317 gm = new DefaultModalGraphMouse<Integer, Number>();
318 vv.setGraphMouse(gm);
319 gm.add(new PopupGraphMousePlugin());
320
321 addBottomControls( jp );
322 vssa.setScaling(true);
323
324 vv.setVertexToolTipTransformer(new VoltageTips<Number>());
325 vv.setToolTipText("<html><center>Use the mouse wheel to zoom<p>Click and Drag the mouse to pan<p>Shift-click and Drag to Rotate</center></html>");
326
327
328
329 return jp;
330 }
331
332
333
334
335
336
337 public Graph<Integer,Number> buildGraph() {
338 Supplier<Graph<Integer,Number>> graphFactory =
339 new Supplier<Graph<Integer,Number>>() {
340 public Graph<Integer,Number> get() {
341 return new SparseMultigraph<Integer,Number>();
342 }
343 };
344 Supplier<Integer> vertexFactory =
345 new Supplier<Integer>() {
346 int count;
347 public Integer get() {
348 return count++;
349 }};
350 Supplier<Number> edgeFactory =
351 new Supplier<Number>() {
352 int count;
353 public Number get() {
354 return count++;
355 }};
356 Graph<Integer,Number> g =
357 MixedRandomGraphGenerator.<Integer,Number>generateMixedRandomGraph(graphFactory, vertexFactory, edgeFactory,
358 edge_weight, 20, seedVertices);
359 es = new NumberFormattingTransformer<Number>(Functions.forMap(edge_weight));
360
361
362
363 if (seedVertices.size() < 2)
364 System.out.println("need at least 2 seeds (one source, one sink)");
365
366
367 boolean source = true;
368 Set<Integer> sources = new HashSet<Integer>();
369 Set<Integer> sinks = new HashSet<Integer>();
370 for(Integer v : seedVertices)
371 {
372 if (source)
373 sources.add(v);
374 else
375 sinks.add(v);
376 source = !source;
377 }
378 VoltageScorer<Integer, Number> voltage_scores =
379 new VoltageScorer<Integer, Number>(g,
380 Functions.forMap(edge_weight), sources, sinks);
381 voltage_scores.evaluate();
382 voltages = new VertexScoreTransformer<Integer, Double>(voltage_scores);
383 vs = new NumberFormattingTransformer<Integer>(voltages);
384
385 Collection<Integer> verts = g.getVertices();
386
387
388 for(Integer v : verts) {
389 transparency.put(v, new Double(0.9));
390 }
391
392
393 Integer v = verts.iterator().next();
394 Number e = new Float(Math.random());
395 edge_weight.put(e, e);
396 g.addEdge(e, v, v);
397 e = new Float(Math.random());
398 edge_weight.put(e, e);
399 g.addEdge(e, v, v);
400 return g;
401 }
402
403
404
405
406 protected void addBottomControls(final JPanel jp)
407 {
408 final JPanel control_panel = new JPanel();
409 jp.add(control_panel, BorderLayout.EAST);
410 control_panel.setLayout(new BorderLayout());
411 final Box vertex_panel = Box.createVerticalBox();
412 vertex_panel.setBorder(BorderFactory.createTitledBorder("Vertices"));
413 final Box edge_panel = Box.createVerticalBox();
414 edge_panel.setBorder(BorderFactory.createTitledBorder("Edges"));
415 final Box both_panel = Box.createVerticalBox();
416
417 control_panel.add(vertex_panel, BorderLayout.NORTH);
418 control_panel.add(edge_panel, BorderLayout.SOUTH);
419 control_panel.add(both_panel, BorderLayout.CENTER);
420
421
422 v_color = new JCheckBox("seed highlight");
423 v_color.addActionListener(this);
424 v_stroke = new JCheckBox("stroke highlight on selection");
425 v_stroke.addActionListener(this);
426 v_labels = new JCheckBox("show voltage values");
427 v_labels.addActionListener(this);
428 v_shape = new JCheckBox("shape by degree");
429 v_shape.addActionListener(this);
430 v_size = new JCheckBox("size by voltage");
431 v_size.addActionListener(this);
432 v_size.setSelected(true);
433 v_aspect = new JCheckBox("stretch by degree ratio");
434 v_aspect.addActionListener(this);
435 v_small = new JCheckBox("filter when degree < " + VertexDisplayPredicate.MIN_DEGREE);
436 v_small.addActionListener(this);
437
438 vertex_panel.add(v_color);
439 vertex_panel.add(v_stroke);
440 vertex_panel.add(v_labels);
441 vertex_panel.add(v_shape);
442 vertex_panel.add(v_size);
443 vertex_panel.add(v_aspect);
444 vertex_panel.add(v_small);
445
446
447 JPanel gradient_panel = new JPanel(new GridLayout(1, 0));
448 gradient_panel.setBorder(BorderFactory.createTitledBorder("Edge paint"));
449 no_gradient = new JRadioButton("Solid color");
450 no_gradient.addActionListener(this);
451 no_gradient.setSelected(true);
452
453
454 gradient_relative = new JRadioButton("Gradient");
455 gradient_relative.addActionListener(this);
456 ButtonGroup bg_grad = new ButtonGroup();
457 bg_grad.add(no_gradient);
458 bg_grad.add(gradient_relative);
459
460 gradient_panel.add(no_gradient);
461
462 gradient_panel.add(gradient_relative);
463
464 JPanel shape_panel = new JPanel(new GridLayout(3,2));
465 shape_panel.setBorder(BorderFactory.createTitledBorder("Edge shape"));
466 e_line = new JRadioButton("line");
467 e_line.addActionListener(this);
468 e_line.setSelected(true);
469
470
471 e_wedge = new JRadioButton("wedge");
472 e_wedge.addActionListener(this);
473 e_quad = new JRadioButton("quad curve");
474 e_quad.addActionListener(this);
475 e_cubic = new JRadioButton("cubic curve");
476 e_cubic.addActionListener(this);
477 e_ortho = new JRadioButton("orthogonal");
478 e_ortho.addActionListener(this);
479 ButtonGroup bg_shape = new ButtonGroup();
480 bg_shape.add(e_line);
481
482 bg_shape.add(e_wedge);
483 bg_shape.add(e_quad);
484 bg_shape.add(e_ortho);
485 bg_shape.add(e_cubic);
486 shape_panel.add(e_line);
487
488 shape_panel.add(e_wedge);
489 shape_panel.add(e_quad);
490 shape_panel.add(e_cubic);
491 shape_panel.add(e_ortho);
492 fill_edges = new JCheckBox("fill edge shapes");
493 fill_edges.setSelected(false);
494 fill_edges.addActionListener(this);
495 shape_panel.add(fill_edges);
496 shape_panel.setOpaque(true);
497 e_color = new JCheckBox("highlight edge weights");
498 e_color.addActionListener(this);
499 e_labels = new JCheckBox("show edge weight values");
500 e_labels.addActionListener(this);
501 e_uarrow_pred = new JCheckBox("undirected");
502 e_uarrow_pred.addActionListener(this);
503 e_darrow_pred = new JCheckBox("directed");
504 e_darrow_pred.addActionListener(this);
505 e_darrow_pred.setSelected(true);
506 e_arrow_centered = new JCheckBox("centered");
507 e_arrow_centered.addActionListener(this);
508 JPanel arrow_panel = new JPanel(new GridLayout(1,0));
509 arrow_panel.setBorder(BorderFactory.createTitledBorder("Show arrows"));
510 arrow_panel.add(e_uarrow_pred);
511 arrow_panel.add(e_darrow_pred);
512 arrow_panel.add(e_arrow_centered);
513
514 e_show_d = new JCheckBox("directed");
515 e_show_d.addActionListener(this);
516 e_show_d.setSelected(true);
517 e_show_u = new JCheckBox("undirected");
518 e_show_u.addActionListener(this);
519 e_show_u.setSelected(true);
520 JPanel show_edge_panel = new JPanel(new GridLayout(1,0));
521 show_edge_panel.setBorder(BorderFactory.createTitledBorder("Show edges"));
522 show_edge_panel.add(e_show_u);
523 show_edge_panel.add(e_show_d);
524
525 shape_panel.setAlignmentX(Component.LEFT_ALIGNMENT);
526 edge_panel.add(shape_panel);
527 gradient_panel.setAlignmentX(Component.LEFT_ALIGNMENT);
528 edge_panel.add(gradient_panel);
529 show_edge_panel.setAlignmentX(Component.LEFT_ALIGNMENT);
530 edge_panel.add(show_edge_panel);
531 arrow_panel.setAlignmentX(Component.LEFT_ALIGNMENT);
532 edge_panel.add(arrow_panel);
533
534 e_color.setAlignmentX(Component.LEFT_ALIGNMENT);
535 edge_panel.add(e_color);
536 e_labels.setAlignmentX(Component.LEFT_ALIGNMENT);
537 edge_panel.add(e_labels);
538
539
540 zoom_at_mouse = new JCheckBox("<html><center>zoom at mouse<p>(wheel only)</center></html>");
541 zoom_at_mouse.addActionListener(this);
542 zoom_at_mouse.setSelected(true);
543
544 final ScalingControl scaler = new CrossoverScalingControl();
545
546 JButton plus = new JButton("+");
547 plus.addActionListener(new ActionListener() {
548 public void actionPerformed(ActionEvent e) {
549 scaler.scale(vv, 1.1f, vv.getCenter());
550 }
551 });
552 JButton minus = new JButton("-");
553 minus.addActionListener(new ActionListener() {
554 public void actionPerformed(ActionEvent e) {
555 scaler.scale(vv, 1/1.1f, vv.getCenter());
556 }
557 });
558
559 JPanel zoomPanel = new JPanel();
560 zoomPanel.setBorder(BorderFactory.createTitledBorder("Zoom"));
561 plus.setAlignmentX(Component.CENTER_ALIGNMENT);
562 zoomPanel.add(plus);
563 minus.setAlignmentX(Component.CENTER_ALIGNMENT);
564 zoomPanel.add(minus);
565 zoom_at_mouse.setAlignmentX(Component.CENTER_ALIGNMENT);
566 zoomPanel.add(zoom_at_mouse);
567
568 JPanel fontPanel = new JPanel();
569
570 font = new JCheckBox("bold text");
571 font.addActionListener(this);
572 font.setAlignmentX(Component.CENTER_ALIGNMENT);
573 fontPanel.add(font);
574
575 both_panel.add(zoomPanel);
576 both_panel.add(fontPanel);
577
578 JComboBox<?> modeBox = gm.getModeComboBox();
579 modeBox.setAlignmentX(Component.CENTER_ALIGNMENT);
580 JPanel modePanel = new JPanel(new BorderLayout()) {
581 public Dimension getMaximumSize() {
582 return getPreferredSize();
583 }
584 };
585 modePanel.setBorder(BorderFactory.createTitledBorder("Mouse Mode"));
586 modePanel.add(modeBox);
587 JPanel comboGrid = new JPanel(new GridLayout(0,1));
588 comboGrid.add(modePanel);
589 fontPanel.add(comboGrid);
590
591
592 JComboBox<Position> cb = new JComboBox<Position>();
593 cb.addItem(Renderer.VertexLabel.Position.N);
594 cb.addItem(Renderer.VertexLabel.Position.NE);
595 cb.addItem(Renderer.VertexLabel.Position.E);
596 cb.addItem(Renderer.VertexLabel.Position.SE);
597 cb.addItem(Renderer.VertexLabel.Position.S);
598 cb.addItem(Renderer.VertexLabel.Position.SW);
599 cb.addItem(Renderer.VertexLabel.Position.W);
600 cb.addItem(Renderer.VertexLabel.Position.NW);
601 cb.addItem(Renderer.VertexLabel.Position.N);
602 cb.addItem(Renderer.VertexLabel.Position.CNTR);
603 cb.addItem(Renderer.VertexLabel.Position.AUTO);
604 cb.addItemListener(new ItemListener() {
605 public void itemStateChanged(ItemEvent e) {
606 Renderer.VertexLabel.Position position =
607 (Renderer.VertexLabel.Position)e.getItem();
608 vv.getRenderer().getVertexLabelRenderer().setPosition(position);
609 vv.repaint();
610 }});
611 cb.setSelectedItem(Renderer.VertexLabel.Position.SE);
612 JPanel positionPanel = new JPanel();
613 positionPanel.setBorder(BorderFactory.createTitledBorder("Label Position"));
614 positionPanel.add(cb);
615
616 comboGrid.add(positionPanel);
617
618 }
619
620 public void actionPerformed(ActionEvent e)
621 {
622 AbstractButton source = (AbstractButton)e.getSource();
623 if (source == v_color)
624 {
625 seedFillColor.setSeedColoring(source.isSelected());
626 }
627 else if (source == e_color)
628 {
629 ewcs.setWeighted(source.isSelected());
630 }
631 else if (source == v_stroke)
632 {
633 vsh.setHighlight(source.isSelected());
634 }
635 else if (source == v_labels)
636 {
637 if (source.isSelected())
638 vv.getRenderContext().setVertexLabelTransformer(vs);
639 else
640 vv.getRenderContext().setVertexLabelTransformer(vs_none);
641 }
642 else if (source == e_labels)
643 {
644 if (source.isSelected())
645 vv.getRenderContext().setEdgeLabelTransformer(es);
646 else
647 vv.getRenderContext().setEdgeLabelTransformer(es_none);
648 }
649 else if (source == e_uarrow_pred)
650 {
651 show_arrow.showUndirected(source.isSelected());
652 }
653 else if (source == e_darrow_pred)
654 {
655 show_arrow.showDirected(source.isSelected());
656 }
657 else if (source == e_arrow_centered)
658 {
659 if(source.isSelected())
660 {
661 vv.getRenderer().getEdgeRenderer().setEdgeArrowRenderingSupport(
662 new CenterEdgeArrowRenderingSupport<Integer, Number>());
663 }
664 else
665 {
666 vv.getRenderer().getEdgeRenderer().setEdgeArrowRenderingSupport(
667 new BasicEdgeArrowRenderingSupport<Integer, Number>());
668 }
669 }
670 else if (source == font)
671 {
672 vff.setBold(source.isSelected());
673 eff.setBold(source.isSelected());
674 }
675 else if (source == v_shape)
676 {
677 vssa.useFunnyShapes(source.isSelected());
678 }
679 else if (source == v_size)
680 {
681 vssa.setScaling(source.isSelected());
682 }
683 else if (source == v_aspect)
684 {
685 vssa.setStretching(source.isSelected());
686 }
687 else if (source == e_line)
688 {
689 if(source.isSelected())
690 {
691 vv.getRenderContext().setEdgeShapeTransformer(EdgeShape.line(graph));
692 }
693 }
694 else if (source == e_ortho)
695 {
696 if (source.isSelected())
697 vv.getRenderContext().setEdgeShapeTransformer(EdgeShape.orthogonal(graph));
698 }
699 else if (source == e_wedge)
700 {
701 if (source.isSelected())
702 vv.getRenderContext().setEdgeShapeTransformer(EdgeShape.wedge(graph, 10));
703 }
704
705
706
707
708
709
710
711 else if (source == e_quad)
712 {
713 if(source.isSelected())
714 {
715 vv.getRenderContext().setEdgeShapeTransformer(EdgeShape.quadCurve(graph));
716 }
717 }
718 else if (source == e_cubic)
719 {
720 if(source.isSelected())
721 {
722 vv.getRenderContext().setEdgeShapeTransformer(EdgeShape.cubicCurve(graph));
723 }
724 }
725 else if (source == e_show_d)
726 {
727 show_edge.showDirected(source.isSelected());
728 }
729 else if (source == e_show_u)
730 {
731 show_edge.showUndirected(source.isSelected());
732 }
733 else if (source == v_small)
734 {
735 show_vertex.filterSmall(source.isSelected());
736 }
737 else if(source == zoom_at_mouse)
738 {
739 gm.setZoomAtMouse(source.isSelected());
740 }
741 else if (source == no_gradient) {
742 if (source.isSelected()) {
743 gradient_level = GRADIENT_NONE;
744 }
745 }
746 else if (source == gradient_relative) {
747 if (source.isSelected()) {
748 gradient_level = GRADIENT_RELATIVE;
749 }
750 }
751 else if (source == fill_edges)
752 {
753 if(source.isSelected()) {
754 vv.getRenderContext().setEdgeFillPaintTransformer( edgeFillPaint );
755 } else {
756 vv.getRenderContext().setEdgeFillPaintTransformer( Functions.<Paint>constant(null) );
757 }
758 }
759 vv.repaint();
760 }
761
762 private final class SeedDrawColor<V> implements Function<V,Paint>
763 {
764 public Paint apply(V v)
765 {
766 return Color.BLACK;
767 }
768 }
769
770 private final class SeedFillColor<V> implements Function<V,Paint>
771 {
772 protected PickedInfo<V> pi;
773 protected final static float dark_value = 0.8f;
774 protected final static float light_value = 0.2f;
775 protected boolean seed_coloring;
776
777 public SeedFillColor(PickedInfo<V> pi)
778 {
779 this.pi = pi;
780 seed_coloring = false;
781 }
782
783 public void setSeedColoring(boolean b)
784 {
785 this.seed_coloring = b;
786 }
787
788 public Paint apply(V v)
789 {
790 float alpha = transparency.get(v).floatValue();
791 if (pi.isPicked(v))
792 {
793 return new Color(1f, 1f, 0, alpha);
794 }
795 else
796 {
797 if (seed_coloring && seedVertices.contains(v))
798 {
799 Color dark = new Color(0, 0, dark_value, alpha);
800 Color light = new Color(0, 0, light_value, alpha);
801 return new GradientPaint( 0, 0, dark, 10, 0, light, true);
802 }
803 else
804 return new Color(1f, 0, 0, alpha);
805 }
806
807 }
808 }
809
810 private final static class EdgeWeightStrokeFunction<E>
811 implements Function<E,Stroke>
812 {
813 protected static final Stroke basic = new BasicStroke(1);
814 protected static final Stroke heavy = new BasicStroke(2);
815 protected static final Stroke dotted = RenderContext.DOTTED;
816
817 protected boolean weighted = false;
818 protected Map<E,Number> edge_weight;
819
820 public EdgeWeightStrokeFunction(Map<E,Number> edge_weight)
821 {
822 this.edge_weight = edge_weight;
823 }
824
825 public void setWeighted(boolean weighted)
826 {
827 this.weighted = weighted;
828 }
829
830 public Stroke apply(E e)
831 {
832 if (weighted)
833 {
834 if (drawHeavy(e))
835 return heavy;
836 else
837 return dotted;
838 }
839 else
840 return basic;
841 }
842
843 protected boolean drawHeavy(E e)
844 {
845 double value = edge_weight.get(e).doubleValue();
846 if (value > 0.7)
847 return true;
848 else
849 return false;
850 }
851
852 }
853
854 private final static class VertexStrokeHighlight<V,E> implements
855 Function<V,Stroke>
856 {
857 protected boolean highlight = false;
858 protected Stroke heavy = new BasicStroke(5);
859 protected Stroke medium = new BasicStroke(3);
860 protected Stroke light = new BasicStroke(1);
861 protected PickedInfo<V> pi;
862 protected Graph<V,E> graph;
863
864 public VertexStrokeHighlight(Graph<V,E> graph, PickedInfo<V> pi)
865 {
866 this.graph = graph;
867 this.pi = pi;
868 }
869
870 public void setHighlight(boolean highlight)
871 {
872 this.highlight = highlight;
873 }
874
875 public Stroke apply(V v)
876 {
877 if (highlight)
878 {
879 if (pi.isPicked(v))
880 return heavy;
881 else
882 {
883 for(V w : graph.getNeighbors(v)) {
884
885
886
887 if (pi.isPicked(w))
888 return medium;
889 }
890 return light;
891 }
892 }
893 else
894 return light;
895 }
896
897 }
898
899 private final static class VertexFontTransformer<V>
900 implements Function<V,Font>
901 {
902 protected boolean bold = false;
903 Font f = new Font("Helvetica", Font.PLAIN, 12);
904 Font b = new Font("Helvetica", Font.BOLD, 12);
905
906 public void setBold(boolean bold)
907 {
908 this.bold = bold;
909 }
910
911 public Font apply(V v)
912 {
913 if (bold)
914 return b;
915 else
916 return f;
917 }
918 }
919
920 private final static class EdgeFontTransformer<E>
921 implements Function<E,Font>
922 {
923 protected boolean bold = false;
924 Font f = new Font("Helvetica", Font.PLAIN, 12);
925 Font b = new Font("Helvetica", Font.BOLD, 12);
926
927 public void setBold(boolean bold)
928 {
929 this.bold = bold;
930 }
931
932 public Font apply(E e)
933 {
934 if (bold)
935 return b;
936 else
937 return f;
938 }
939 }
940 private final static class DirectionDisplayPredicate<V,E>
941 implements Predicate<Context<Graph<V,E>,E>>
942
943 {
944 protected boolean show_d;
945 protected boolean show_u;
946
947 public DirectionDisplayPredicate(boolean show_d, boolean show_u)
948 {
949 this.show_d = show_d;
950 this.show_u = show_u;
951 }
952
953 public void showDirected(boolean b)
954 {
955 show_d = b;
956 }
957
958 public void showUndirected(boolean b)
959 {
960 show_u = b;
961 }
962
963 public boolean apply(Context<Graph<V,E>,E> context)
964 {
965 Graph<V,E> graph = context.graph;
966 E e = context.element;
967 if (graph.getEdgeType(e) == EdgeType.DIRECTED && show_d) {
968 return true;
969 }
970 if (graph.getEdgeType(e) == EdgeType.UNDIRECTED && show_u) {
971 return true;
972 }
973 return false;
974 }
975 }
976
977 private final static class VertexDisplayPredicate<V,E>
978 implements Predicate<Context<Graph<V,E>,V>>
979
980 {
981 protected boolean filter_small;
982 protected final static int MIN_DEGREE = 4;
983
984 public VertexDisplayPredicate(boolean filter)
985 {
986 this.filter_small = filter;
987 }
988
989 public void filterSmall(boolean b)
990 {
991 filter_small = b;
992 }
993
994 public boolean apply(Context<Graph<V,E>,V> context) {
995 Graph<V,E> graph = context.graph;
996 V v = context.element;
997
998 if (filter_small)
999 return (graph.degree(v) >= MIN_DEGREE);
1000 else
1001 return true;
1002 }
1003 }
1004
1005
1006
1007
1008
1009
1010 private final static class VertexShapeSizeAspect<V,E>
1011 extends AbstractVertexShapeTransformer <V>
1012 implements Function<V,Shape> {
1013
1014 protected boolean stretch = false;
1015 protected boolean scale = false;
1016 protected boolean funny_shapes = false;
1017 protected Function<V,Double> voltages;
1018 protected Graph<V,E> graph;
1019
1020
1021 public VertexShapeSizeAspect(Graph<V,E> graphIn, Function<V,Double> voltagesIn)
1022 {
1023 this.graph = graphIn;
1024 this.voltages = voltagesIn;
1025 setSizeTransformer(new Function<V,Integer>() {
1026
1027 public Integer apply(V v) {
1028 if (scale)
1029 return (int)(voltages.apply(v) * 30) + 20;
1030 else
1031 return 20;
1032
1033 }});
1034 setAspectRatioTransformer(new Function<V,Float>() {
1035
1036 public Float apply(V v) {
1037 if (stretch) {
1038 return (float)(graph.inDegree(v) + 1) /
1039 (graph.outDegree(v) + 1);
1040 } else {
1041 return 1.0f;
1042 }
1043 }});
1044 }
1045
1046 public void setStretching(boolean stretch)
1047 {
1048 this.stretch = stretch;
1049 }
1050
1051 public void setScaling(boolean scale)
1052 {
1053 this.scale = scale;
1054 }
1055
1056 public void useFunnyShapes(boolean use)
1057 {
1058 this.funny_shapes = use;
1059 }
1060
1061 public Shape apply(V v)
1062 {
1063 if (funny_shapes)
1064 {
1065 if (graph.degree(v) < 5)
1066 {
1067 int sides = Math.max(graph.degree(v), 3);
1068 return factory.getRegularPolygon(v, sides);
1069 }
1070 else
1071 return factory.getRegularStar(v, graph.degree(v));
1072 }
1073 else
1074 return factory.getEllipse(v);
1075 }
1076 }
1077
1078
1079
1080
1081
1082 protected class PopupGraphMousePlugin extends AbstractPopupGraphMousePlugin
1083 implements MouseListener {
1084
1085 public PopupGraphMousePlugin() {
1086 this(MouseEvent.BUTTON3_MASK);
1087 }
1088 public PopupGraphMousePlugin(int modifiers) {
1089 super(modifiers);
1090 }
1091
1092
1093
1094
1095
1096
1097
1098 @SuppressWarnings("unchecked")
1099 protected void handlePopup(MouseEvent e) {
1100 final VisualizationViewer<Integer,Number> vv =
1101 (VisualizationViewer<Integer,Number>)e.getSource();
1102 Point2D p = e.getPoint();
1103
1104 GraphElementAccessor<Integer,Number> pickSupport = vv.getPickSupport();
1105 if(pickSupport != null) {
1106 final Integer v = pickSupport.getVertex(vv.getGraphLayout(), p.getX(), p.getY());
1107 if(v != null) {
1108 JPopupMenu popup = new JPopupMenu();
1109 popup.add(new AbstractAction("Decrease Transparency") {
1110 public void actionPerformed(ActionEvent e) {
1111 Double value = Math.min(1,
1112 transparency.get(v).doubleValue()+0.1);
1113 transparency.put(v, value);
1114
1115
1116
1117 vv.repaint();
1118 }
1119 });
1120 popup.add(new AbstractAction("Increase Transparency"){
1121 public void actionPerformed(ActionEvent e) {
1122 Double value = Math.max(0,
1123 transparency.get(v).doubleValue()-0.1);
1124 transparency.put(v, value);
1125
1126
1127 vv.repaint();
1128 }
1129 });
1130 popup.show(vv, e.getX(), e.getY());
1131 } else {
1132 final Number edge = pickSupport.getEdge(vv.getGraphLayout(), p.getX(), p.getY());
1133 if(edge != null) {
1134 JPopupMenu popup = new JPopupMenu();
1135 popup.add(new AbstractAction(edge.toString()) {
1136 public void actionPerformed(ActionEvent e) {
1137 System.err.println("got "+edge);
1138 }
1139 });
1140 popup.show(vv, e.getX(), e.getY());
1141
1142 }
1143 }
1144 }
1145 }
1146 }
1147
1148 public class VoltageTips<E>
1149 implements Function<Integer,String> {
1150
1151 public String apply(Integer vertex) {
1152 return "Voltage:"+voltages.apply(vertex);
1153 }
1154 }
1155
1156 public class GradientPickedEdgePaintFunction<V,E> extends GradientEdgePaintTransformer<V,E>
1157 {
1158 private Function<E,Paint> defaultFunc;
1159 protected boolean fill_edge = false;
1160 Predicate<Context<Graph<V,E>,E>> selfLoop = new SelfLoopEdgePredicate<V,E>();
1161
1162 public GradientPickedEdgePaintFunction(Function<E,Paint> defaultEdgePaintFunction,
1163 VisualizationViewer<V,E> vv)
1164 {
1165 super(Color.WHITE, Color.BLACK, vv);
1166 this.defaultFunc = defaultEdgePaintFunction;
1167 }
1168
1169 public void useFill(boolean b)
1170 {
1171 fill_edge = b;
1172 }
1173
1174 public Paint apply(E e) {
1175 if (gradient_level == GRADIENT_NONE) {
1176 return defaultFunc.apply(e);
1177 } else {
1178 return super.apply(e);
1179 }
1180 }
1181
1182 protected Color getColor2(E e)
1183 {
1184 return vv.getPickedEdgeState().isPicked(e)? Color.CYAN : c2;
1185 }
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195 }
1196
1197 }
1198