package kbl.language;
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.Collection;
import java.util.HashSet;
import java.util.Set;
import java.util.Vector;
import java.util.Map.Entry;
import javax.swing.BorderFactory;
import javax.swing.DefaultListCellRenderer;
import javax.swing.JApplet;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JList;
import javax.swing.JPanel;
import kbl.language.DFAWalker;
import kbl.language.StrategyNFA2DFA;
import kbl.language.testDFAStateWrapper;
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.SparseMultigraph;
import edu.uci.ics.jung.graph.util.EdgeType;
import edu.uci.ics.jung.visualization.GraphZoomScrollPane;
import edu.uci.ics.jung.visualization.VisualizationViewer;
import edu.uci.ics.jung.visualization.control.DefaultModalGraphMouse;
import edu.uci.ics.jung.visualization.control.ModalGraphMouse;
import edu.uci.ics.jung.visualization.decorators.EllipseVertexShapeTransformer;
import edu.uci.ics.jung.visualization.decorators.PickableEdgePaintTransformer;
import edu.uci.ics.jung.visualization.decorators.PickableVertexPaintTransformer;
import edu.uci.ics.jung.visualization.decorators.ToStringLabeller;
import edu.uci.ics.jung.visualization.layout.LayoutTransition;
import edu.uci.ics.jung.visualization.renderers.EdgeLabelRenderer;
import edu.uci.ics.jung.visualization.renderers.Renderer;
import edu.uci.ics.jung.visualization.renderers.VertexLabelRenderer;
import edu.uci.ics.jung.visualization.subLayout.GraphCollapser;
import edu.uci.ics.jung.visualization.util.Animator;
public class DFAdrawer extends JApplet {
private static final long serialVersionUID = 1526716590965776504L;
Layout<Vertex, Edge> layout;
VisualizationViewer<Vertex, Edge> viewer;
Graph<Vertex, Edge> graph;
Graph<Vertex, Edge> collapsedGraph;
GraphCollapser collapser;
VertexLabelRenderer vertexLabelRenderer;
EdgeLabelRenderer edgeLabelRenderer;
final Set<Edge> exclusions = new HashSet<Edge>();
private DFAWalker it;
public DFAdrawer(StrategyNFA2DFA dfa) {
this.it = (DFAWalker) dfa.getIterator();
draw();
}
public void clearState() {
it.clearState();
draw();
}
public void draw() {
graph = new SparseMultigraph<Vertex, Edge>();
/*
* Vertex v1 = new Vertex(1); Vertex v2 = new Vertex(2); Vertex v3 = new
* Vertex(3); Vertex v4 = new Vertex(4); graph.addVertex(v1);
* graph.addVertex(v2); graph.addVertex(v3); graph.addVertex(v4);
* graph.addEdge(new Edge("edge", v1, v2), v1, v2, EdgeType.DIRECTED);
* graph.addEdge(new Edge("edge", v2, v1), v2, v1, EdgeType.DIRECTED);
* graph.addEdge(new Edge("edge", v2, v3), v2, v3, EdgeType.DIRECTED);
* graph.addEdge(new Edge("edge", v4, v4), v1, v4, EdgeType.DIRECTED);
*/
while (it.hasNext()) {
testDFAStateWrapper subgraph = it.next();
Vertex from = new Vertex(subgraph.id, subgraph.match, subgraph.name);
graph.addVertex(from);
for (Entry<String, testDFAStateWrapper> entry : subgraph.cc2DFAMap
.entrySet()) {
Vertex to = new Vertex(entry.getValue().id, entry
.getValue().match, entry.getValue().name);
graph.addVertex(to);
graph.addEdge(new Edge(entry.getKey().toString(), from, to),
from, to, EdgeType.DIRECTED);
}
}
collapsedGraph = graph;
collapser = new GraphCollapser(graph);
layout = new FRLayout<Vertex, Edge>(graph);
viewer = new VisualizationViewer<Vertex, Edge>(layout, new Dimension(
600, 400));
viewer.setBackground(Color.white);
viewer.getRenderer().getVertexLabelRenderer()
.setPosition(Renderer.VertexLabel.Position.CNTR);
viewer.getRenderContext().setVertexLabelTransformer(
new ToStringLabeller<Vertex>());
viewer.getRenderContext().setEdgeLabelTransformer(
new ToStringLabeller<Edge>());
/*
* Transformer<Edge, String> stringer = new Transformer<Edge, String>()
* { public String transform(Edge e) { return "Edge:" +
* graph.getEndpoints(e).toString(); } };
*
* vv.getRenderContext().setEdgeLabelTransformer(stringer);
*/
viewer.getRenderContext().setVertexShapeTransformer(
new ClusterVertexShapeFunction<Vertex>());
viewer.getRenderContext().setEdgeDrawPaintTransformer(
new PickableEdgePaintTransformer<Edge>(viewer
.getPickedEdgeState(), Color.black, Color.cyan));
viewer.getRenderContext().setVertexFillPaintTransformer(
new PickableVertexPaintTransformer<Vertex>(viewer
.getPickedVertexState(), Color.red, Color.yellow));
// create a form to hold the graph
final GraphZoomScrollPane panel = new GraphZoomScrollPane(viewer);
Container content = getContentPane();
content.add(panel);
final DefaultModalGraphMouse<Integer, Number> graphMouse = new DefaultModalGraphMouse<Integer, Number>();
viewer.setGraphMouse(graphMouse);
graphMouse.setMode(ModalGraphMouse.Mode.PICKING);
initialGUI(content, graphMouse);
}
private void initialGUI(Container content,
final DefaultModalGraphMouse<Integer, Number> graphMouse) {
Vector<Class<? extends Layout<Vertex, Edge>>> combos = getCombos();
final JComboBox jcb = new JComboBox(combos);
// use a renderer to shorten the layout name presentation
jcb.setRenderer(new DefaultListCellRenderer() {
private static final long serialVersionUID = 2886015296102490146L;
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, viewer));
jcb.setSelectedItem(CircleLayout.class);
JButton collapse = new JButton("Collapse");
collapse.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
Collection<Vertex> picked = new HashSet<Vertex>(viewer
.getPickedVertexState().getPicked());
if (picked.size() > 1) {
Graph<Vertex, Edge> inGraph = layout.getGraph();
@SuppressWarnings("unchecked")
Graph<Vertex, Edge> clusterGraph = collapser
.getClusterGraph(inGraph, picked);
@SuppressWarnings("unchecked")
Graph<Vertex, Edge> g = collapser.collapse(
layout.getGraph(), clusterGraph);
collapsedGraph = g;
double sumx = 0;
double sumy = 0;
for (Object v : picked) {
if (v instanceof Vertex) {
Point2D p = (Point2D) layout.transform((Vertex) v);
sumx += p.getX();
sumy += p.getY();
}
}
Point2D cp = new Point2D.Double(sumx / picked.size(), sumy
/ picked.size());
viewer.getRenderContext().getParallelEdgeIndexFunction()
.reset();
layout.setGraph(g);
layout.setLocation(null, cp);
viewer.getPickedVertexState().clear();
viewer.repaint();
}
}
});
JButton expand = new JButton("Expand");
expand.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
Collection<Vertex> picked = new HashSet<Vertex>(viewer
.getPickedVertexState().getPicked());
for (Object v : picked) {
if (v instanceof Graph) {
@SuppressWarnings("unchecked")
Graph<Vertex, Edge> g = collapser.expand(
layout.getGraph(), (Graph<?, ?>) v);
viewer.getRenderContext()
.getParallelEdgeIndexFunction().reset();
layout.setGraph(g);
}
viewer.getPickedVertexState().clear();
viewer.repaint();
}
}
});
JButton reset = new JButton("Reset");
reset.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
clearState();
layout.setGraph(graph);
exclusions.clear();
viewer.repaint();
}
});
JPanel collapseControls = new JPanel(new GridLayout(3, 1));
collapseControls.setBorder(BorderFactory.createTitledBorder("Picked"));
collapseControls.add(collapse);
collapseControls.add(expand);
collapseControls.add(reset);
JPanel modePanel = new JPanel(new GridLayout(2, 1));
modePanel.setBorder(BorderFactory.createTitledBorder("Mouse Mode"));
modePanel.add(graphMouse.getModeComboBox());
JPanel controls = new JPanel();
controls.add(modePanel);
controls.add(jcb);
controls.add(collapseControls);
content.add(controls, BorderLayout.SOUTH);
}
class ClusterVertexShapeFunction<V> extends
EllipseVertexShapeTransformer<V> {
ClusterVertexShapeFunction() {
setSizeTransformer(new ClusterVertexSizeFunction<V>(20));
}
@Override
public Shape transform(V v) {
if (v instanceof Graph) {
@SuppressWarnings("unchecked")
int size = ((Graph<Vertex, Edge>) 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);
}
}
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<Vertex, Edge> vv;
private LayoutChooser(JComboBox jcb,
VisualizationViewer<Vertex, Edge> vv2) {
super();
this.jcb = jcb;
this.vv = vv2;
}
public void actionPerformed(ActionEvent arg0) {
Object[] constructorArgs = { graph };
@SuppressWarnings("unchecked")
Class<? extends Layout<Integer, Number>> layoutC = (Class<? extends Layout<Integer, Number>>) jcb
.getSelectedItem();
try {
Constructor<? extends Layout<Integer, Number>> constructor = layoutC
.getConstructor(new Class[] { Graph.class });
Object o = constructor.newInstance(constructorArgs);
@SuppressWarnings("unchecked")
Layout<Vertex, Edge> l = (Layout<Vertex, Edge>) o;
l.setInitializer(vv.getGraphLayout());
l.setSize(vv.getSize());
layout = l;
LayoutTransition<Vertex, Edge> lt = new LayoutTransition<Vertex, Edge>(
vv, vv.getGraphLayout(), l);
Animator animator = new Animator(lt);
animator.start();
vv.getRenderContext().getMultiLayerTransformer()
.setToIdentity();
vv.repaint();
} catch (Exception e) {
e.printStackTrace();
}
}
}
@SuppressWarnings("unchecked")
private Vector<Class<? extends Layout<Vertex, Edge>>> getCombos() {
Vector<Class<? extends Layout<Vertex, Edge>>> layouts = new Vector<Class<? extends Layout<Vertex, Edge>>>();
layouts.add((Class<? extends Layout<Vertex, Edge>>) KKLayout.class);
layouts.add((Class<? extends Layout<Vertex, Edge>>) FRLayout.class);
layouts.add((Class<? extends Layout<Vertex, Edge>>) CircleLayout.class);
layouts.add((Class<? extends Layout<Vertex, Edge>>) SpringLayout.class);
layouts.add((Class<? extends Layout<Vertex, Edge>>) SpringLayout2.class);
layouts.add((Class<? extends Layout<Vertex, Edge>>) ISOMLayout.class);
return layouts;
}
static class Vertex {
int id;
String name;
boolean match;
Vertex(int id) {
this.id = id;
}
Vertex(int id, boolean match, String name) {
this.id = id;
this.match = match;
this.name = name;
}
@Override
public String toString() {
if (match)
//return Integer.toString(id) + '*';
return '*'+this.name;
else
//return Integer.toString(id);
return this.name;
}
@Override
public int hashCode() {
return id;
}
@Override
public boolean equals(Object other) {
if (other instanceof Vertex) {
Vertex that = (Vertex) other;
return this.id == that.id;
}
return false;
}
}
static class Edge {
String id;
String desc;
Edge(String st, Vertex from, Vertex to) {
this.desc = st;
this.id = Integer.toString(from.id) + '-' + Integer.toString(to.id);
}
@Override
public String toString() {
return desc;
}
@Override
public int hashCode() {
return id.hashCode();
}
@Override
public boolean equals(Object other) {
if (other instanceof Edge) {
Edge that = (Edge) other;
return this.id.equals(that.id);
}
return false;
}
}
}