Java tutorial
/* * Copyright (c) 2003, 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. * */ package edu.uci.ics.jung.samples; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Component; import java.awt.Container; import java.awt.Dimension; import java.awt.GridLayout; import java.awt.Shape; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.geom.Point2D; import java.lang.reflect.Constructor; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.List; import java.util.Set; import javax.swing.BorderFactory; import javax.swing.DefaultListCellRenderer; import javax.swing.JApplet; import javax.swing.JButton; import javax.swing.JComboBox; import javax.swing.JComponent; import javax.swing.JFrame; import javax.swing.JList; import javax.swing.JOptionPane; import javax.swing.JPanel; import org.apache.commons.collections15.Predicate; import org.apache.commons.collections15.Transformer; import edu.uci.ics.jung.algorithms.layout.CircleLayout; import edu.uci.ics.jung.algorithms.layout.FRLayout; import edu.uci.ics.jung.algorithms.layout.ISOMLayout; import edu.uci.ics.jung.algorithms.layout.KKLayout; import edu.uci.ics.jung.algorithms.layout.Layout; import edu.uci.ics.jung.algorithms.layout.SpringLayout; import edu.uci.ics.jung.algorithms.layout.SpringLayout2; import edu.uci.ics.jung.graph.Graph; import edu.uci.ics.jung.graph.util.Pair; import edu.uci.ics.jung.graph.util.TestGraphs; import edu.uci.ics.jung.visualization.DefaultVisualizationModel; import edu.uci.ics.jung.visualization.GraphZoomScrollPane; import edu.uci.ics.jung.visualization.VisualizationModel; import edu.uci.ics.jung.visualization.VisualizationViewer; import edu.uci.ics.jung.visualization.control.CrossoverScalingControl; import edu.uci.ics.jung.visualization.control.DefaultModalGraphMouse; import edu.uci.ics.jung.visualization.control.ModalGraphMouse; import edu.uci.ics.jung.visualization.control.ScalingControl; import edu.uci.ics.jung.visualization.decorators.EllipseVertexShapeTransformer; import edu.uci.ics.jung.visualization.decorators.ToStringLabeller; import edu.uci.ics.jung.visualization.layout.LayoutTransition; import edu.uci.ics.jung.visualization.subLayout.GraphCollapser; import edu.uci.ics.jung.visualization.util.Animator; import edu.uci.ics.jung.visualization.util.PredicatedParallelEdgeIndexFunction; /** * A demo that shows how collections of vertices can be collapsed * into a single vertex. In this demo, the vertices that are * collapsed are those mouse-picked by the user. Any criteria * could be used to form the vertex collections to be collapsed, * perhaps some common characteristic of those vertex objects. * * Note that the collection types don't use generics in this * demo, because the vertices are of two types: String for plain * vertices, and Graph<String,Number> for the collapsed vertices. * * @author Tom Nelson * */ @SuppressWarnings({ "serial", "rawtypes", "unchecked" }) public class VertexCollapseDemoWithLayouts extends JApplet { String instructions = "<html>Use the mouse to select multiple vertices" + "<p>either by dragging a region, or by shift-clicking" + "<p>on multiple vertices." + "<p>After you select vertices, use the Collapse button" + "<p>to combine them into a single vertex." + "<p>Select a 'collapsed' vertex and use the Expand button" + "<p>to restore the collapsed vertices." + "<p>The Restore button will restore the original graph." + "<p>If you select 2 (and only 2) vertices, then press" + "<p>the Compress Edges button, parallel edges between" + "<p>those two vertices will no longer be expanded." + "<p>If you select 2 (and only 2) vertices, then press" + "<p>the Expand Edges button, parallel edges between" + "<p>those two vertices will be expanded." + "<p>You can drag the vertices with the mouse." + "<p>Use the 'Picking'/'Transforming' combo-box to switch" + "<p>between picking and transforming mode.</html>"; /** * the graph */ Graph graph; Graph collapsedGraph; /** * the visual component and renderer for the graph */ VisualizationViewer vv; Layout layout; GraphCollapser collapser; public VertexCollapseDemoWithLayouts() { // create a simple graph for the demo graph = TestGraphs.getOneComponentGraph(); collapsedGraph = graph; collapser = new GraphCollapser(graph); layout = new FRLayout(graph); Dimension preferredSize = new Dimension(400, 400); final VisualizationModel visualizationModel = new DefaultVisualizationModel(layout, preferredSize); vv = new VisualizationViewer(visualizationModel, preferredSize); vv.getRenderContext().setVertexShapeTransformer(new ClusterVertexShapeFunction()); final PredicatedParallelEdgeIndexFunction eif = PredicatedParallelEdgeIndexFunction.getInstance(); final Set exclusions = new HashSet(); eif.setPredicate(new Predicate() { public boolean evaluate(Object e) { return exclusions.contains(e); } }); vv.getRenderContext().setParallelEdgeIndexFunction(eif); vv.setBackground(Color.white); // add a listener for ToolTips vv.setVertexToolTipTransformer(new ToStringLabeller() { /* (non-Javadoc) * @see edu.uci.ics.jung.visualization.decorators.DefaultToolTipFunction#getToolTipText(java.lang.Object) */ @Override public String transform(Object v) { if (v instanceof Graph) { return ((Graph) v).getVertices().toString(); } return super.transform(v); } }); /** * the regular graph mouse for the normal view */ final DefaultModalGraphMouse graphMouse = new DefaultModalGraphMouse(); vv.setGraphMouse(graphMouse); Container content = getContentPane(); GraphZoomScrollPane gzsp = new GraphZoomScrollPane(vv); content.add(gzsp); JComboBox modeBox = graphMouse.getModeComboBox(); modeBox.addItemListener(graphMouse.getModeListener()); graphMouse.setMode(ModalGraphMouse.Mode.PICKING); 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()); } }); JButton collapse = new JButton("Collapse"); collapse.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { Collection picked = new HashSet(vv.getPickedVertexState().getPicked()); if (picked.size() > 1) { Graph inGraph = layout.getGraph(); Graph clusterGraph = collapser.getClusterGraph(inGraph, picked); Graph g = collapser.collapse(layout.getGraph(), clusterGraph); collapsedGraph = g; double sumx = 0; double sumy = 0; for (Object v : picked) { Point2D p = (Point2D) layout.transform(v); sumx += p.getX(); sumy += p.getY(); } Point2D cp = new Point2D.Double(sumx / picked.size(), sumy / picked.size()); vv.getRenderContext().getParallelEdgeIndexFunction().reset(); layout.setGraph(g); layout.setLocation(clusterGraph, cp); vv.getPickedVertexState().clear(); vv.repaint(); } } }); JButton compressEdges = new JButton("Compress Edges"); compressEdges.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { Collection picked = vv.getPickedVertexState().getPicked(); if (picked.size() == 2) { Pair pair = new Pair(picked); Graph graph = layout.getGraph(); Collection edges = new HashSet(graph.getIncidentEdges(pair.getFirst())); edges.retainAll(graph.getIncidentEdges(pair.getSecond())); exclusions.addAll(edges); vv.repaint(); } } }); JButton expandEdges = new JButton("Expand Edges"); expandEdges.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { Collection picked = vv.getPickedVertexState().getPicked(); if (picked.size() == 2) { Pair pair = new Pair(picked); Graph graph = layout.getGraph(); Collection edges = new HashSet(graph.getIncidentEdges(pair.getFirst())); edges.retainAll(graph.getIncidentEdges(pair.getSecond())); exclusions.removeAll(edges); vv.repaint(); } } }); JButton expand = new JButton("Expand"); expand.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { Collection picked = new HashSet(vv.getPickedVertexState().getPicked()); for (Object v : picked) { if (v instanceof Graph) { Graph g = collapser.expand(layout.getGraph(), (Graph) v); vv.getRenderContext().getParallelEdgeIndexFunction().reset(); layout.setGraph(g); } vv.getPickedVertexState().clear(); vv.repaint(); } } }); JButton reset = new JButton("Reset"); reset.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { layout.setGraph(graph); exclusions.clear(); vv.repaint(); } }); JButton help = new JButton("Help"); help.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { JOptionPane.showMessageDialog((JComponent) e.getSource(), instructions, "Help", JOptionPane.PLAIN_MESSAGE); } }); Class[] combos = getCombos(); final JComboBox jcb = new JComboBox(combos); // use a renderer to shorten the layout name presentation jcb.setRenderer(new DefaultListCellRenderer() { public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { String valueString = value.toString(); valueString = valueString.substring(valueString.lastIndexOf('.') + 1); return super.getListCellRendererComponent(list, valueString, index, isSelected, cellHasFocus); } }); jcb.addActionListener(new LayoutChooser(jcb, vv)); jcb.setSelectedItem(FRLayout.class); JPanel controls = new JPanel(); JPanel zoomControls = new JPanel(new GridLayout(2, 1)); zoomControls.setBorder(BorderFactory.createTitledBorder("Zoom")); zoomControls.add(plus); zoomControls.add(minus); controls.add(zoomControls); JPanel collapseControls = new JPanel(new GridLayout(3, 1)); collapseControls.setBorder(BorderFactory.createTitledBorder("Picked")); collapseControls.add(collapse); collapseControls.add(expand); collapseControls.add(compressEdges); collapseControls.add(expandEdges); collapseControls.add(reset); controls.add(collapseControls); controls.add(modeBox); controls.add(help); controls.add(jcb); content.add(controls, BorderLayout.SOUTH); } /** * a demo class that will create a vertex shape that is either a * polygon or star. The number of sides corresponds to the number * of vertices that were collapsed into the vertex represented by * this shape. * * @author Tom Nelson * * @param <V> */ class ClusterVertexShapeFunction<V> extends EllipseVertexShapeTransformer<V> { ClusterVertexShapeFunction() { setSizeTransformer(new ClusterVertexSizeFunction<V>(20)); } @Override public Shape transform(V v) { if (v instanceof Graph) { int size = ((Graph) v).getVertexCount(); if (size < 8) { int sides = Math.max(size, 3); return factory.getRegularPolygon(v, sides); } else { return factory.getRegularStar(v, size); } } return super.transform(v); } } /** * A demo class that will make vertices larger if they represent * a collapsed collection of original vertices * @author Tom Nelson * * @param <V> */ class ClusterVertexSizeFunction<V> implements Transformer<V, Integer> { int size; public ClusterVertexSizeFunction(Integer size) { this.size = size; } public Integer transform(V v) { if (v instanceof Graph) { return 30; } return size; } } private class LayoutChooser implements ActionListener { private final JComboBox jcb; private final VisualizationViewer vv; private LayoutChooser(JComboBox jcb, VisualizationViewer vv) { super(); this.jcb = jcb; this.vv = vv; } public void actionPerformed(ActionEvent arg0) { Object[] constructorArgs = { collapsedGraph }; Class<? extends Layout> layoutC = (Class<? extends Layout>) jcb.getSelectedItem(); // Class lay = layoutC; try { Constructor<? extends Layout> constructor = layoutC.getConstructor(new Class[] { Graph.class }); Object o = constructor.newInstance(constructorArgs); Layout l = (Layout) o; l.setInitializer(vv.getGraphLayout()); l.setSize(vv.getSize()); layout = l; LayoutTransition lt = new LayoutTransition(vv, vv.getGraphLayout(), l); Animator animator = new Animator(lt); animator.start(); vv.getRenderContext().getMultiLayerTransformer().setToIdentity(); vv.repaint(); } catch (Exception e) { e.printStackTrace(); } } } /** * @return */ private Class<? extends Layout>[] getCombos() { List<Class<? extends Layout>> layouts = new ArrayList<Class<? extends Layout>>(); layouts.add(KKLayout.class); layouts.add(FRLayout.class); layouts.add(CircleLayout.class); layouts.add(SpringLayout.class); layouts.add(SpringLayout2.class); layouts.add(ISOMLayout.class); return layouts.toArray(new Class[0]); } /** * a driver for this demo */ public static void main(String[] args) { JFrame f = new JFrame(); f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); f.getContentPane().add(new VertexCollapseDemoWithLayouts()); f.pack(); f.setVisible(true); } }