Java tutorial
/* * Copyright (c) 2004, the JUNG Project and the Regents of the University of * California All rights reserved. * * This software is open-source under the BSD license; see either "license.txt" * or http://jung.sourceforge.net/license.txt for a description. * * * Created on Nov 7, 2004 */ package edu.uci.ics.jung.samples; import java.awt.BasicStroke; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Component; import java.awt.Dimension; import java.awt.Font; import java.awt.GradientPaint; import java.awt.GridLayout; import java.awt.Paint; import java.awt.Shape; import java.awt.Stroke; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.awt.geom.Point2D; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import javax.swing.AbstractAction; import javax.swing.AbstractButton; import javax.swing.BorderFactory; import javax.swing.Box; import javax.swing.ButtonGroup; import javax.swing.JApplet; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JComboBox; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.JPopupMenu; import javax.swing.JRadioButton; import org.apache.commons.collections15.Factory; import org.apache.commons.collections15.Predicate; import org.apache.commons.collections15.Transformer; import org.apache.commons.collections15.functors.ConstantTransformer; import org.apache.commons.collections15.functors.MapTransformer; import edu.uci.ics.jung.algorithms.generators.random.MixedRandomGraphGenerator; import edu.uci.ics.jung.algorithms.layout.FRLayout; import edu.uci.ics.jung.algorithms.layout.GraphElementAccessor; import edu.uci.ics.jung.algorithms.layout.Layout; import edu.uci.ics.jung.algorithms.scoring.VoltageScorer; import edu.uci.ics.jung.algorithms.scoring.util.VertexScoreTransformer; import edu.uci.ics.jung.algorithms.util.SelfLoopEdgePredicate; import edu.uci.ics.jung.graph.Graph; import edu.uci.ics.jung.graph.SparseMultigraph; import edu.uci.ics.jung.graph.util.Context; import edu.uci.ics.jung.graph.util.EdgeType; import edu.uci.ics.jung.visualization.GraphZoomScrollPane; import edu.uci.ics.jung.visualization.RenderContext; import edu.uci.ics.jung.visualization.VisualizationViewer; import edu.uci.ics.jung.visualization.control.AbstractPopupGraphMousePlugin; import edu.uci.ics.jung.visualization.control.CrossoverScalingControl; import edu.uci.ics.jung.visualization.control.DefaultModalGraphMouse; import edu.uci.ics.jung.visualization.control.ScalingControl; import edu.uci.ics.jung.visualization.decorators.AbstractVertexShapeTransformer; import edu.uci.ics.jung.visualization.decorators.EdgeShape; import edu.uci.ics.jung.visualization.decorators.GradientEdgePaintTransformer; import edu.uci.ics.jung.visualization.decorators.NumberFormattingTransformer; import edu.uci.ics.jung.visualization.decorators.PickableEdgePaintTransformer; import edu.uci.ics.jung.visualization.picking.PickedInfo; import edu.uci.ics.jung.visualization.picking.PickedState; import edu.uci.ics.jung.visualization.renderers.BasicEdgeArrowRenderingSupport; import edu.uci.ics.jung.visualization.renderers.CenterEdgeArrowRenderingSupport; import edu.uci.ics.jung.visualization.renderers.Renderer; /** * Shows off some of the capabilities of <code>PluggableRenderer</code>. * This code provides examples of different ways to provide and * change the various functions that provide property information * to the renderer. * * <p>This demo creates a random mixed-mode graph with random edge * weights using <code>TestGraph.generateMixedRandomGraph</code>. * It then runs <code>VoltageRanker</code> on this graph, using half * of the "seed" vertices from the random graph generation as * voltage sources, and half of them as voltage sinks.</p> * * <p>What the controls do: * <ul> * <li/>Mouse controls: * <ul> * <li/>If your mouse has a scroll wheel, scrolling forward zooms out and * scrolling backward zooms in. * <li/>Left-clicking on a vertex or edge selects it, and unselects all others. * <li/>Middle-clicking on a vertex or edge toggles its selection state. * <li/>Right-clicking on a vertex brings up a pop-up menu that allows you to * increase or decrease that vertex's transparency. * <li/>Left-clicking on the background allows you to drag the image around. * <li/>Hovering over a vertex tells you what its voltage is; hovering over an * edge shows its identity; hovering over the background shows an informational * message. </ul> * <li/>Vertex stuff: * <ul> * <li/>"vertex seed coloring": if checked, the seed vertices are colored blue, * and all other vertices are colored red. Otherwise, all vertices are colored * a slightly transparent red (except the currently "picked" vertex, which is * colored transparent purple). * <li/>"vertex selection stroke highlighting": if checked, the picked vertex * and its neighbors are all drawn with heavy borders. Otherwise, all vertices * are drawn with light borders. * <li/>"show vertex ranks (voltages)": if checked, each vertex is labeled with its * calculated 'voltage'. Otherwise, vertices are unlabeled. * <li/>"vertex degree shapes": if checked, vertices are drawn with a polygon with * number of sides proportional to its degree. Otherwise, vertices are drawn * as ellipses. * <li/>"vertex voltage size": if checked, vertices are drawn with a size * proportional to their voltage ranking. Otherwise, all vertices are drawn * at the same size. * <li/>"vertex degree ratio stretch": if checked, vertices are drawn with an * aspect ratio (height/width ratio) proportional to the ratio of their indegree to * their outdegree. Otherwise, vertices are drawn with an aspect ratio of 1. * <li/>"filter vertices of degree < 4": if checked, does not display any vertices * (or their incident edges) whose degree in the original graph is less than 4; * otherwise, all vertices are drawn. * </ul> * <li/>Edge stuff: * <ul> * <li/>"edge shape": selects between lines, wedges, quadratic curves, and cubic curves * for drawing edges. * <li/>"fill edge shapes": if checked, fills the edge shapes. This will have no effect * if "line" is selected. * <li/>"edge paint": selects between solid colored edges, and gradient-painted edges. * Gradient painted edges are darkest in the middle for undirected edges, and darkest * at the destination for directed edges. * <li/>"show edges": only edges of the checked types are drawn. * <li/>"show arrows": only arrows whose edges are of the checked types are drawn. * <li/>"edge weight highlighting": if checked, edges with weight greater than * a threshold value are drawn using thick solid lines, and other edges are drawn * using thin gray dotted lines. (This combines edge stroke and paint.) Otherwise, * all edges are drawn with thin solid lines. * <li/>"show edge weights": if checked, edges are labeled with their weights. * Otherwise, edges are not labeled. * </ul> * <li/>Miscellaneous (center panel) * <ul> * <li/>"bold text": if checked, all vertex and edge labels are drawn using a * boldface font. Otherwise, a normal-weight font is used. (Has no effect if * no labels are currently visible.) * <li/>zoom controls: * <ul> * <li/>"+" zooms in, "-" zooms out * <li/>"zoom at mouse (wheel only)": if checked, zooming (using the mouse * scroll wheel) is centered on the location of the mouse pointer; otherwise, * it is centered on the center of the visualization pane. * </ul> * </ul> * </p> * * @author Danyel Fisher, Joshua O'Madadhain, Tom Nelson */ @SuppressWarnings("serial") public class PluggableRendererDemo extends JApplet implements ActionListener { protected JCheckBox v_color; protected JCheckBox e_color; protected JCheckBox v_stroke; protected JCheckBox e_uarrow_pred; protected JCheckBox e_darrow_pred; protected JCheckBox e_arrow_centered; protected JCheckBox v_shape; protected JCheckBox v_size; protected JCheckBox v_aspect; protected JCheckBox v_labels; protected JRadioButton e_line; protected JRadioButton e_bent; protected JRadioButton e_wedge; protected JRadioButton e_quad; protected JRadioButton e_ortho; protected JRadioButton e_cubic; protected JCheckBox e_labels; protected JCheckBox font; protected JCheckBox e_show_d; protected JCheckBox e_show_u; protected JCheckBox v_small; protected JCheckBox zoom_at_mouse; protected JCheckBox fill_edges; protected JRadioButton no_gradient; protected JRadioButton gradient_relative; protected static final int GRADIENT_NONE = 0; protected static final int GRADIENT_RELATIVE = 1; protected static int gradient_level = GRADIENT_NONE; protected SeedFillColor<Integer> seedFillColor; protected SeedDrawColor<Integer> seedDrawColor; protected EdgeWeightStrokeFunction<Number> ewcs; protected VertexStrokeHighlight<Integer, Number> vsh; protected Transformer<Integer, String> vs; protected Transformer<Integer, String> vs_none; protected Transformer<Number, String> es; protected Transformer<Number, String> es_none; protected VertexFontTransformer<Integer> vff; protected EdgeFontTransformer<Number> eff; protected VertexShapeSizeAspect<Integer, Number> vssa; protected DirectionDisplayPredicate<Integer, Number> show_edge; protected DirectionDisplayPredicate<Integer, Number> show_arrow; protected VertexDisplayPredicate<Integer, Number> show_vertex; protected Predicate<Context<Graph<Integer, Number>, Number>> self_loop; protected GradientPickedEdgePaintFunction<Integer, Number> edgeDrawPaint; protected GradientPickedEdgePaintFunction<Integer, Number> edgeFillPaint; protected final static Object VOLTAGE_KEY = "voltages"; protected final static Object TRANSPARENCY = "transparency"; protected Map<Number, Number> edge_weight = new HashMap<Number, Number>(); protected Transformer<Integer, Double> voltages; protected Map<Integer, Number> transparency = new HashMap<Integer, Number>(); protected VisualizationViewer<Integer, Number> vv; protected DefaultModalGraphMouse<Integer, Number> gm; protected Set<Integer> seedVertices = new HashSet<Integer>(); public void start() { getContentPane().add(startFunction()); } public static void main(String[] s) { JFrame jf = new JFrame(); jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); JPanel jp = new PluggableRendererDemo().startFunction(); jf.getContentPane().add(jp); jf.pack(); jf.setVisible(true); } @SuppressWarnings({ "unchecked", "rawtypes" }) public JPanel startFunction() { Graph<Integer, Number> g = getGraph(); Layout<Integer, Number> layout = new FRLayout<Integer, Number>(g); // layout.setSize(new Dimension(5000,5000)); vv = new VisualizationViewer<Integer, Number>(layout); PickedState<Integer> picked_state = vv.getPickedVertexState(); // affineTransformer = vv.getLayoutTransformer(); self_loop = new SelfLoopEdgePredicate<Integer, Number>(); // create decorators seedFillColor = new SeedFillColor<Integer>(picked_state); seedDrawColor = new SeedDrawColor<Integer>(picked_state); ewcs = new EdgeWeightStrokeFunction<Number>(edge_weight); vsh = new VertexStrokeHighlight<Integer, Number>(g, picked_state); vff = new VertexFontTransformer<Integer>(); eff = new EdgeFontTransformer<Number>(); vs_none = new ConstantTransformer(null); es_none = new ConstantTransformer(null); vssa = new VertexShapeSizeAspect<Integer, Number>(g, voltages); show_edge = new DirectionDisplayPredicate<Integer, Number>(true, true); show_arrow = new DirectionDisplayPredicate<Integer, Number>(true, false); show_vertex = new VertexDisplayPredicate<Integer, Number>(false); // uses a gradient edge if unpicked, otherwise uses picked selection edgeDrawPaint = new GradientPickedEdgePaintFunction<Integer, Number>( new PickableEdgePaintTransformer<Number>(vv.getPickedEdgeState(), Color.black, Color.cyan), vv); edgeFillPaint = new GradientPickedEdgePaintFunction<Integer, Number>( new PickableEdgePaintTransformer<Number>(vv.getPickedEdgeState(), Color.black, Color.cyan), vv); vv.getRenderContext().setVertexFillPaintTransformer(seedFillColor); vv.getRenderContext().setVertexDrawPaintTransformer(seedDrawColor); vv.getRenderContext().setVertexStrokeTransformer(vsh); vv.getRenderContext().setVertexLabelTransformer(vs_none); vv.getRenderContext().setVertexFontTransformer(vff); vv.getRenderContext().setVertexShapeTransformer(vssa); vv.getRenderContext().setVertexIncludePredicate(show_vertex); vv.getRenderContext().setEdgeDrawPaintTransformer(edgeDrawPaint); vv.getRenderContext().setEdgeLabelTransformer(es_none); vv.getRenderContext().setEdgeFontTransformer(eff); vv.getRenderContext().setEdgeStrokeTransformer(ewcs); vv.getRenderContext().setEdgeIncludePredicate(show_edge); vv.getRenderContext().setEdgeShapeTransformer(new EdgeShape.Line<Integer, Number>()); vv.getRenderContext().setEdgeArrowPredicate(show_arrow); vv.getRenderContext().setArrowFillPaintTransformer(new ConstantTransformer(Color.lightGray)); vv.getRenderContext().setArrowDrawPaintTransformer(new ConstantTransformer(Color.black)); JPanel jp = new JPanel(); jp.setLayout(new BorderLayout()); vv.setBackground(Color.white); GraphZoomScrollPane scrollPane = new GraphZoomScrollPane(vv); jp.add(scrollPane); gm = new DefaultModalGraphMouse<Integer, Number>(); vv.setGraphMouse(gm); gm.add(new PopupGraphMousePlugin()); addBottomControls(jp); vssa.setScaling(true); vv.setVertexToolTipTransformer(new VoltageTips<Number>()); 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>"); return jp; } /** * Generates a mixed-mode random graph, runs VoltageRanker on it, and * returns the resultant graph. */ public Graph<Integer, Number> getGraph() { Factory<Graph<Integer, Number>> graphFactory = new Factory<Graph<Integer, Number>>() { public Graph<Integer, Number> create() { return new SparseMultigraph<Integer, Number>(); } }; Factory<Integer> vertexFactory = new Factory<Integer>() { int count; public Integer create() { return count++; } }; Factory<Number> edgeFactory = new Factory<Number>() { int count; public Number create() { return count++; } }; Graph<Integer, Number> g = MixedRandomGraphGenerator.<Integer, Number>generateMixedRandomGraph(graphFactory, vertexFactory, edgeFactory, edge_weight, 20, false, seedVertices); es = new NumberFormattingTransformer<Number>(MapTransformer.getInstance(edge_weight)); // collect the seeds used to define the random graph if (seedVertices.size() < 2) System.out.println("need at least 2 seeds (one source, one sink)"); // use these seeds as source and sink vertices, run VoltageRanker boolean source = true; Set<Integer> sources = new HashSet<Integer>(); Set<Integer> sinks = new HashSet<Integer>(); for (Integer v : seedVertices) { if (source) sources.add(v); else sinks.add(v); source = !source; } VoltageScorer<Integer, Number> voltage_scores = new VoltageScorer<Integer, Number>(g, MapTransformer.getInstance(edge_weight), sources, sinks); voltage_scores.evaluate(); voltages = new VertexScoreTransformer<Integer, Double>(voltage_scores); vs = new NumberFormattingTransformer<Integer>(voltages); Collection<Integer> verts = g.getVertices(); // assign a transparency value of 0.9 to all vertices for (Integer v : verts) { transparency.put(v, new Double(0.9)); } // add a couple of self-loops (sanity check on rendering) Integer v = verts.iterator().next(); Number e = new Float(Math.random()); edge_weight.put(e, e); g.addEdge(e, v, v); e = new Float(Math.random()); edge_weight.put(e, e); g.addEdge(e, v, v); return g; } /** * @param jp panel to which controls will be added */ @SuppressWarnings({ "rawtypes", "unchecked" }) protected void addBottomControls(final JPanel jp) { final JPanel control_panel = new JPanel(); jp.add(control_panel, BorderLayout.EAST); control_panel.setLayout(new BorderLayout()); final Box vertex_panel = Box.createVerticalBox(); vertex_panel.setBorder(BorderFactory.createTitledBorder("Vertices")); final Box edge_panel = Box.createVerticalBox(); edge_panel.setBorder(BorderFactory.createTitledBorder("Edges")); final Box both_panel = Box.createVerticalBox(); control_panel.add(vertex_panel, BorderLayout.NORTH); control_panel.add(edge_panel, BorderLayout.SOUTH); control_panel.add(both_panel, BorderLayout.CENTER); // set up vertex controls v_color = new JCheckBox("seed highlight"); v_color.addActionListener(this); v_stroke = new JCheckBox("stroke highlight on selection"); v_stroke.addActionListener(this); v_labels = new JCheckBox("show voltage values"); v_labels.addActionListener(this); v_shape = new JCheckBox("shape by degree"); v_shape.addActionListener(this); v_size = new JCheckBox("size by voltage"); v_size.addActionListener(this); v_size.setSelected(true); v_aspect = new JCheckBox("stretch by degree ratio"); v_aspect.addActionListener(this); v_small = new JCheckBox("filter when degree < " + VertexDisplayPredicate.MIN_DEGREE); v_small.addActionListener(this); vertex_panel.add(v_color); vertex_panel.add(v_stroke); vertex_panel.add(v_labels); vertex_panel.add(v_shape); vertex_panel.add(v_size); vertex_panel.add(v_aspect); vertex_panel.add(v_small); // set up edge controls JPanel gradient_panel = new JPanel(new GridLayout(1, 0)); gradient_panel.setBorder(BorderFactory.createTitledBorder("Edge paint")); no_gradient = new JRadioButton("Solid color"); no_gradient.addActionListener(this); no_gradient.setSelected(true); // gradient_absolute = new JRadioButton("Absolute gradient"); // gradient_absolute.addActionListener(this); gradient_relative = new JRadioButton("Gradient"); gradient_relative.addActionListener(this); ButtonGroup bg_grad = new ButtonGroup(); bg_grad.add(no_gradient); bg_grad.add(gradient_relative); //bg_grad.add(gradient_absolute); gradient_panel.add(no_gradient); //gradientGrid.add(gradient_absolute); gradient_panel.add(gradient_relative); JPanel shape_panel = new JPanel(new GridLayout(3, 2)); shape_panel.setBorder(BorderFactory.createTitledBorder("Edge shape")); e_line = new JRadioButton("line"); e_line.addActionListener(this); e_line.setSelected(true); // e_bent = new JRadioButton("bent line"); // e_bent.addActionListener(this); e_wedge = new JRadioButton("wedge"); e_wedge.addActionListener(this); e_quad = new JRadioButton("quad curve"); e_quad.addActionListener(this); e_cubic = new JRadioButton("cubic curve"); e_cubic.addActionListener(this); e_ortho = new JRadioButton("orthogonal"); e_ortho.addActionListener(this); ButtonGroup bg_shape = new ButtonGroup(); bg_shape.add(e_line); // bg.add(e_bent); bg_shape.add(e_wedge); bg_shape.add(e_quad); bg_shape.add(e_ortho); bg_shape.add(e_cubic); shape_panel.add(e_line); // shape_panel.add(e_bent); shape_panel.add(e_wedge); shape_panel.add(e_quad); shape_panel.add(e_cubic); shape_panel.add(e_ortho); fill_edges = new JCheckBox("fill edge shapes"); fill_edges.setSelected(false); fill_edges.addActionListener(this); shape_panel.add(fill_edges); shape_panel.setOpaque(true); e_color = new JCheckBox("highlight edge weights"); e_color.addActionListener(this); e_labels = new JCheckBox("show edge weight values"); e_labels.addActionListener(this); e_uarrow_pred = new JCheckBox("undirected"); e_uarrow_pred.addActionListener(this); e_darrow_pred = new JCheckBox("directed"); e_darrow_pred.addActionListener(this); e_darrow_pred.setSelected(true); e_arrow_centered = new JCheckBox("centered"); e_arrow_centered.addActionListener(this); JPanel arrow_panel = new JPanel(new GridLayout(1, 0)); arrow_panel.setBorder(BorderFactory.createTitledBorder("Show arrows")); arrow_panel.add(e_uarrow_pred); arrow_panel.add(e_darrow_pred); arrow_panel.add(e_arrow_centered); e_show_d = new JCheckBox("directed"); e_show_d.addActionListener(this); e_show_d.setSelected(true); e_show_u = new JCheckBox("undirected"); e_show_u.addActionListener(this); e_show_u.setSelected(true); JPanel show_edge_panel = new JPanel(new GridLayout(1, 0)); show_edge_panel.setBorder(BorderFactory.createTitledBorder("Show edges")); show_edge_panel.add(e_show_u); show_edge_panel.add(e_show_d); shape_panel.setAlignmentX(Component.LEFT_ALIGNMENT); edge_panel.add(shape_panel); gradient_panel.setAlignmentX(Component.LEFT_ALIGNMENT); edge_panel.add(gradient_panel); show_edge_panel.setAlignmentX(Component.LEFT_ALIGNMENT); edge_panel.add(show_edge_panel); arrow_panel.setAlignmentX(Component.LEFT_ALIGNMENT); edge_panel.add(arrow_panel); e_color.setAlignmentX(Component.LEFT_ALIGNMENT); edge_panel.add(e_color); e_labels.setAlignmentX(Component.LEFT_ALIGNMENT); edge_panel.add(e_labels); // set up zoom controls zoom_at_mouse = new JCheckBox("<html><center>zoom at mouse<p>(wheel only)</center></html>"); zoom_at_mouse.addActionListener(this); zoom_at_mouse.setSelected(true); final ScalingControl scaler = new CrossoverScalingControl(); JButton plus = new JButton("+"); plus.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { scaler.scale(vv, 1.1f, vv.getCenter()); } }); JButton minus = new JButton("-"); minus.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { scaler.scale(vv, 1 / 1.1f, vv.getCenter()); } }); JPanel zoomPanel = new JPanel(); zoomPanel.setBorder(BorderFactory.createTitledBorder("Zoom")); plus.setAlignmentX(Component.CENTER_ALIGNMENT); zoomPanel.add(plus); minus.setAlignmentX(Component.CENTER_ALIGNMENT); zoomPanel.add(minus); zoom_at_mouse.setAlignmentX(Component.CENTER_ALIGNMENT); zoomPanel.add(zoom_at_mouse); JPanel fontPanel = new JPanel(); // add font and zoom controls to center panel font = new JCheckBox("bold text"); font.addActionListener(this); font.setAlignmentX(Component.CENTER_ALIGNMENT); fontPanel.add(font); both_panel.add(zoomPanel); both_panel.add(fontPanel); JComboBox modeBox = gm.getModeComboBox(); modeBox.setAlignmentX(Component.CENTER_ALIGNMENT); JPanel modePanel = new JPanel(new BorderLayout()) { public Dimension getMaximumSize() { return getPreferredSize(); } }; modePanel.setBorder(BorderFactory.createTitledBorder("Mouse Mode")); modePanel.add(modeBox); JPanel comboGrid = new JPanel(new GridLayout(0, 1)); comboGrid.add(modePanel); fontPanel.add(comboGrid); JComboBox cb = new JComboBox(); cb.addItem(Renderer.VertexLabel.Position.N); cb.addItem(Renderer.VertexLabel.Position.NE); cb.addItem(Renderer.VertexLabel.Position.E); cb.addItem(Renderer.VertexLabel.Position.SE); cb.addItem(Renderer.VertexLabel.Position.S); cb.addItem(Renderer.VertexLabel.Position.SW); cb.addItem(Renderer.VertexLabel.Position.W); cb.addItem(Renderer.VertexLabel.Position.NW); cb.addItem(Renderer.VertexLabel.Position.N); cb.addItem(Renderer.VertexLabel.Position.CNTR); cb.addItem(Renderer.VertexLabel.Position.AUTO); cb.addItemListener(new ItemListener() { public void itemStateChanged(ItemEvent e) { Renderer.VertexLabel.Position position = (Renderer.VertexLabel.Position) e.getItem(); vv.getRenderer().getVertexLabelRenderer().setPosition(position); vv.repaint(); } }); cb.setSelectedItem(Renderer.VertexLabel.Position.SE); JPanel positionPanel = new JPanel(); positionPanel.setBorder(BorderFactory.createTitledBorder("Label Position")); positionPanel.add(cb); comboGrid.add(positionPanel); } @SuppressWarnings({ "rawtypes", "unchecked" }) public void actionPerformed(ActionEvent e) { AbstractButton source = (AbstractButton) e.getSource(); if (source == v_color) { seedDrawColor.setSeedColoring(source.isSelected()); seedFillColor.setSeedColoring(source.isSelected()); } else if (source == e_color) { ewcs.setWeighted(source.isSelected()); } else if (source == v_stroke) { vsh.setHighlight(source.isSelected()); } else if (source == v_labels) { if (source.isSelected()) vv.getRenderContext().setVertexLabelTransformer(vs); else vv.getRenderContext().setVertexLabelTransformer(vs_none); } else if (source == e_labels) { if (source.isSelected()) vv.getRenderContext().setEdgeLabelTransformer(es); else vv.getRenderContext().setEdgeLabelTransformer(es_none); } else if (source == e_uarrow_pred) { show_arrow.showUndirected(source.isSelected()); } else if (source == e_darrow_pred) { show_arrow.showDirected(source.isSelected()); } else if (source == e_arrow_centered) { if (source.isSelected()) { vv.getRenderer().getEdgeRenderer() .setEdgeArrowRenderingSupport(new CenterEdgeArrowRenderingSupport()); } else { vv.getRenderer().getEdgeRenderer() .setEdgeArrowRenderingSupport(new BasicEdgeArrowRenderingSupport()); } } else if (source == font) { vff.setBold(source.isSelected()); eff.setBold(source.isSelected()); } else if (source == v_shape) { vssa.useFunnyShapes(source.isSelected()); } else if (source == v_size) { vssa.setScaling(source.isSelected()); } else if (source == v_aspect) { vssa.setStretching(source.isSelected()); } else if (source == e_line) { if (source.isSelected()) { vv.getRenderContext().setEdgeShapeTransformer(new EdgeShape.Line<Integer, Number>()); } } else if (source == e_ortho) { if (source.isSelected()) vv.getRenderContext().setEdgeShapeTransformer(new EdgeShape.Orthogonal<Integer, Number>()); } else if (source == e_wedge) { if (source.isSelected()) vv.getRenderContext().setEdgeShapeTransformer(new EdgeShape.Wedge<Integer, Number>(10)); } // else if (source == e_bent) // { // if(source.isSelected()) // { // vv.getRenderContext().setEdgeShapeFunction(new EdgeShape.BentLine()); // } // } else if (source == e_quad) { if (source.isSelected()) { vv.getRenderContext().setEdgeShapeTransformer(new EdgeShape.QuadCurve<Integer, Number>()); } } else if (source == e_cubic) { if (source.isSelected()) { vv.getRenderContext().setEdgeShapeTransformer(new EdgeShape.CubicCurve<Integer, Number>()); } } else if (source == e_show_d) { show_edge.showDirected(source.isSelected()); } else if (source == e_show_u) { show_edge.showUndirected(source.isSelected()); } else if (source == v_small) { show_vertex.filterSmall(source.isSelected()); } else if (source == zoom_at_mouse) { gm.setZoomAtMouse(source.isSelected()); } else if (source == no_gradient) { if (source.isSelected()) { gradient_level = GRADIENT_NONE; } // } else if (source == gradient_absolute) { // if (source.isSelected()) { // gradient_level = GRADIENT_ABSOLUTE; // } } else if (source == gradient_relative) { if (source.isSelected()) { gradient_level = GRADIENT_RELATIVE; } } else if (source == fill_edges) { if (source.isSelected()) { vv.getRenderContext().setEdgeFillPaintTransformer(edgeFillPaint); } else { vv.getRenderContext().setEdgeFillPaintTransformer(new ConstantTransformer(null)); } // edgePaint.useFill(source.isSelected()); } vv.repaint(); } private final class SeedDrawColor<V> implements Transformer<V, Paint> { @SuppressWarnings("unused") protected PickedInfo<V> pi; @SuppressWarnings("unused") protected final static float dark_value = 0.8f; @SuppressWarnings("unused") protected final static float light_value = 0.2f; @SuppressWarnings("unused") protected boolean seed_coloring; public SeedDrawColor(PickedInfo<V> pi) { this.pi = pi; seed_coloring = false; } public void setSeedColoring(boolean b) { this.seed_coloring = b; } public Paint transform(V v) { return Color.BLACK; } // public Paint getFillPaint(V v) // { // float alpha = transparency.get(v).floatValue(); // if (pi.isPicked(v)) // { // return new Color(1f, 1f, 0, alpha); // } // else // { // if (seed_coloring && seedVertices.contains(v)) // { // Color dark = new Color(0, 0, dark_value, alpha); // Color light = new Color(0, 0, light_value, alpha); // return new GradientPaint( 0, 0, dark, 10, 0, light, true); // } // else // return new Color(1f, 0, 0, alpha); // } // // } } private final class SeedFillColor<V> implements Transformer<V, Paint> { protected PickedInfo<V> pi; protected final static float dark_value = 0.8f; protected final static float light_value = 0.2f; protected boolean seed_coloring; public SeedFillColor(PickedInfo<V> pi) { this.pi = pi; seed_coloring = false; } public void setSeedColoring(boolean b) { this.seed_coloring = b; } // public Paint getDrawPaint(V v) // { // return Color.BLACK; // } public Paint transform(V v) { float alpha = transparency.get(v).floatValue(); if (pi.isPicked(v)) { return new Color(1f, 1f, 0, alpha); } else { if (seed_coloring && seedVertices.contains(v)) { Color dark = new Color(0, 0, dark_value, alpha); Color light = new Color(0, 0, light_value, alpha); return new GradientPaint(0, 0, dark, 10, 0, light, true); } else return new Color(1f, 0, 0, alpha); } } } private final static class EdgeWeightStrokeFunction<E> implements Transformer<E, Stroke> { protected static final Stroke basic = new BasicStroke(1); protected static final Stroke heavy = new BasicStroke(2); protected static final Stroke dotted = RenderContext.DOTTED; protected boolean weighted = false; protected Map<E, Number> edge_weight; public EdgeWeightStrokeFunction(Map<E, Number> edge_weight) { this.edge_weight = edge_weight; } public void setWeighted(boolean weighted) { this.weighted = weighted; } public Stroke transform(E e) { if (weighted) { if (drawHeavy(e)) return heavy; else return dotted; } else return basic; } protected boolean drawHeavy(E e) { double value = edge_weight.get(e).doubleValue(); if (value > 0.7) return true; else return false; } } private final static class VertexStrokeHighlight<V, E> implements Transformer<V, Stroke> { protected boolean highlight = false; protected Stroke heavy = new BasicStroke(5); protected Stroke medium = new BasicStroke(3); protected Stroke light = new BasicStroke(1); protected PickedInfo<V> pi; protected Graph<V, E> graph; public VertexStrokeHighlight(Graph<V, E> graph, PickedInfo<V> pi) { this.graph = graph; this.pi = pi; } public void setHighlight(boolean highlight) { this.highlight = highlight; } public Stroke transform(V v) { if (highlight) { if (pi.isPicked(v)) return heavy; else { for (V w : graph.getNeighbors(v)) { // for (Iterator iter = graph.getNeighbors(v)v.getNeighbors().iterator(); iter.hasNext(); ) // { // Vertex w = (Vertex)iter.next(); if (pi.isPicked(w)) return medium; } return light; } } else return light; } } private final static class VertexFontTransformer<V> implements Transformer<V, Font> { protected boolean bold = false; Font f = new Font("Helvetica", Font.PLAIN, 12); Font b = new Font("Helvetica", Font.BOLD, 12); public void setBold(boolean bold) { this.bold = bold; } public Font transform(V v) { if (bold) return b; else return f; } } private final static class EdgeFontTransformer<E> implements Transformer<E, Font> { protected boolean bold = false; Font f = new Font("Helvetica", Font.PLAIN, 12); Font b = new Font("Helvetica", Font.BOLD, 12); public void setBold(boolean bold) { this.bold = bold; } public Font transform(E e) { if (bold) return b; else return f; } } private final static class DirectionDisplayPredicate<V, E> implements Predicate<Context<Graph<V, E>, E>> //extends AbstractGraphPredicate<V,E> { protected boolean show_d; protected boolean show_u; public DirectionDisplayPredicate(boolean show_d, boolean show_u) { this.show_d = show_d; this.show_u = show_u; } public void showDirected(boolean b) { show_d = b; } public void showUndirected(boolean b) { show_u = b; } public boolean evaluate(Context<Graph<V, E>, E> context) { Graph<V, E> graph = context.graph; E e = context.element; if (graph.getEdgeType(e) == EdgeType.DIRECTED && show_d) { return true; } if (graph.getEdgeType(e) == EdgeType.UNDIRECTED && show_u) { return true; } return false; } } private final static class VertexDisplayPredicate<V, E> implements Predicate<Context<Graph<V, E>, V>> // extends AbstractGraphPredicate<V,E> { protected boolean filter_small; protected final static int MIN_DEGREE = 4; public VertexDisplayPredicate(boolean filter) { this.filter_small = filter; } public void filterSmall(boolean b) { filter_small = b; } public boolean evaluate(Context<Graph<V, E>, V> context) { Graph<V, E> graph = context.graph; V v = context.element; // Vertex v = (Vertex)arg0; if (filter_small) return (graph.degree(v) >= MIN_DEGREE); else return true; } } /** * Controls the shape, size, and aspect ratio for each vertex. * * @author Joshua O'Madadhain */ private final static class VertexShapeSizeAspect<V, E> extends AbstractVertexShapeTransformer<V> implements Transformer<V, Shape> { protected boolean stretch = false; protected boolean scale = false; protected boolean funny_shapes = false; protected Transformer<V, Double> voltages; protected Graph<V, E> graph; // protected AffineTransform scaleTransform = new AffineTransform(); public VertexShapeSizeAspect(Graph<V, E> graphIn, Transformer<V, Double> voltagesIn) { this.graph = graphIn; this.voltages = voltagesIn; setSizeTransformer(new Transformer<V, Integer>() { public Integer transform(V v) { if (scale) return (int) (voltages.transform(v) * 30) + 20; else return 20; } }); setAspectRatioTransformer(new Transformer<V, Float>() { public Float transform(V v) { if (stretch) { return (float) (graph.inDegree(v) + 1) / (graph.outDegree(v) + 1); } else { return 1.0f; } } }); } public void setStretching(boolean stretch) { this.stretch = stretch; } public void setScaling(boolean scale) { this.scale = scale; } public void useFunnyShapes(boolean use) { this.funny_shapes = use; } public Shape transform(V v) { if (funny_shapes) { if (graph.degree(v) < 5) { int sides = Math.max(graph.degree(v), 3); return factory.getRegularPolygon(v, sides); } else return factory.getRegularStar(v, graph.degree(v)); } else return factory.getEllipse(v); } } /** * a GraphMousePlugin that offers popup * menu support */ protected class PopupGraphMousePlugin extends AbstractPopupGraphMousePlugin implements MouseListener { public PopupGraphMousePlugin() { this(MouseEvent.BUTTON3_MASK); } public PopupGraphMousePlugin(int modifiers) { super(modifiers); } /** * If this event is over a Vertex, pop up a menu to * allow the user to increase/decrease the voltage * attribute of this Vertex * @param e */ @SuppressWarnings("unchecked") protected void handlePopup(MouseEvent e) { final VisualizationViewer<Integer, Number> vv = (VisualizationViewer<Integer, Number>) e.getSource(); Point2D p = e.getPoint();//vv.getRenderContext().getBasicTransformer().inverseViewTransform(e.getPoint()); GraphElementAccessor<Integer, Number> pickSupport = vv.getPickSupport(); if (pickSupport != null) { final Integer v = pickSupport.getVertex(vv.getGraphLayout(), p.getX(), p.getY()); if (v != null) { JPopupMenu popup = new JPopupMenu(); popup.add(new AbstractAction("Decrease Transparency") { public void actionPerformed(ActionEvent e) { Double value = Math.min(1, transparency.get(v).doubleValue() + 0.1); transparency.put(v, value); // transparency.put(v, )transparency.get(v); // MutableDouble value = (MutableDouble)transparency.getNumber(v); // value.setDoubleValue(Math.min(1, value.doubleValue() + 0.1)); vv.repaint(); } }); popup.add(new AbstractAction("Increase Transparency") { public void actionPerformed(ActionEvent e) { Double value = Math.max(0, transparency.get(v).doubleValue() - 0.1); transparency.put(v, value); // MutableDouble value = (MutableDouble)transparency.getNumber(v); // value.setDoubleValue(Math.max(0, value.doubleValue() - 0.1)); vv.repaint(); } }); popup.show(vv, e.getX(), e.getY()); } else { final Number edge = pickSupport.getEdge(vv.getGraphLayout(), p.getX(), p.getY()); if (edge != null) { JPopupMenu popup = new JPopupMenu(); popup.add(new AbstractAction(edge.toString()) { public void actionPerformed(ActionEvent e) { System.err.println("got " + edge); } }); popup.show(vv, e.getX(), e.getY()); } } } } } public class VoltageTips<E> implements Transformer<Integer, String> { public String transform(Integer vertex) { return "Voltage:" + voltages.transform(vertex); } } public class GradientPickedEdgePaintFunction<V, E> extends GradientEdgePaintTransformer<V, E> { private Transformer<E, Paint> defaultFunc; protected boolean fill_edge = false; Predicate<Context<Graph<V, E>, E>> selfLoop = new SelfLoopEdgePredicate<V, E>(); public GradientPickedEdgePaintFunction(Transformer<E, Paint> defaultEdgePaintFunction, VisualizationViewer<V, E> vv) { super(Color.WHITE, Color.BLACK, vv); this.defaultFunc = defaultEdgePaintFunction; } public void useFill(boolean b) { fill_edge = b; } public Paint transform(E e) { if (gradient_level == GRADIENT_NONE) { return defaultFunc.transform(e); } else { return super.transform(e); } } protected Color getColor2(E e) { return vv.getPickedEdgeState().isPicked(e) ? Color.CYAN : c2; } // public Paint getFillPaint(E e) // { // if (selfLoop.evaluateEdge(vv.getGraphLayout().getGraph(), e) || !fill_edge) // return null; // else // return getDrawPaint(e); // } } }