/*
* Copyright (C) 2014 GG-Net GmbH - Oliver Günther.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; If not, see <http://www.gnu.org/licenses/>.
*/
package eu.ggnet.statemachine.swing;
import java.awt.BasicStroke;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import javax.swing.JFrame;
import org.apache.commons.collections15.Transformer;
import org.apache.commons.collections15.functors.ConstantTransformer;
import eu.ggnet.statemachine.Link;
import eu.ggnet.statemachine.State;
import eu.ggnet.statemachine.StateFormater;
import eu.ggnet.statemachine.StateMachine;
import edu.uci.ics.jung.algorithms.layout.FRLayout;
import edu.uci.ics.jung.graph.DirectedGraph;
import edu.uci.ics.jung.graph.DirectedSparseMultigraph;
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.ToStringLabeller;
import edu.uci.ics.jung.visualization.renderers.DefaultVertexLabelRenderer;
import edu.uci.ics.jung.visualization.renderers.GradientVertexRenderer;
import edu.uci.ics.jung.visualization.renderers.Renderer;
import edu.uci.ics.jung.visualization.renderers.VertexLabelAsShapeRenderer;
/**
* Class for displaing Ui Informations.
* <p/>
* @author oliver.guenther
*/
public class Grapher {
/**
* Show an exact subgraph of the suplied states.
* <p/>
* @param <T> type of state machine
* @param stateMachine the state machine
* @param states the states to display
*/
public <T> void showExact(final StateMachine<T> stateMachine, State<T>... states) {
showExact(stateMachine, null, states);
}
/**
* Show an exact subgraph of the suplied states.
* <p/>
* @param <T> type of state machine
* @param stateMachine the state machine
* @param formater an optional formater
* @param states the states to display
*/
public <T> void showExact(final StateMachine<T> stateMachine, final StateFormater<T> formater, State<T>... states) {
StateMachine small = new StateMachine(stateMachine);
Set<State<T>> subStates = new HashSet<>(Arrays.asList(states));
for (Link<T> link : stateMachine.getLinks()) {
if ( subStates.contains(link.getSource()) && subStates.contains(link.getDestination()) ) {
small.add(link);
}
}
showFull(small, formater);
}
/**
* Show a greedy subgraph of the suplied states.
* <p/>
* @param <T> type of state machine
* @param stateMachine the state machine
* @param states the states and all directly connected to display
*/
public <T> void showGreedy(final StateMachine<T> stateMachine, State<T>... states) {
showGreedy(stateMachine, null, states);
}
/**
* Show a greedy subgraph of the suplied states.
* <p/>
* @param <T> type of state machine
* @param stateMachine the state machine
* @param formater an optional formater
* @param states the states and all directly connected to display
*/
public <T> void showGreedy(final StateMachine<T> stateMachine, final StateFormater<T> formater, State<T>... states) {
StateMachine small = new StateMachine(stateMachine);
Set<State<T>> subStates = new HashSet<>(Arrays.asList(states));
for (Link<T> link : stateMachine.getLinks()) {
if ( subStates.contains(link.getSource()) || subStates.contains(link.getDestination()) ) {
small.add(link);
}
}
showFull(small, formater);
}
/**
* Show the full StateMachine with a special formater.
* <p/>
* @param <T> type of state machine
* @param stateMachine the statemachine to show
*/
public static <T> void showFull(final StateMachine<T> stateMachine) {
showFull(stateMachine, null);
}
/**
* Show the full StateMachine with a special formater.
* <p/>
* @param <T> type of state machine
* @param stateMachine the statemachine to show
* @param formater an optional formater
*/
public static <T> void showFull(final StateMachine<T> stateMachine, final StateFormater<T> formater) {
DirectedGraph<State<T>, String> g = new DirectedSparseMultigraph<>();
int i = 0;
for (Link<T> link : stateMachine.getLinks()) {
// TODO: A Graph needs for each transition a unique id. A StateMachine not. So we build it here.
g.addEdge("[" + (i++) + "] " + link.getTransition().toString(), link.getSource(), link.getDestination());
}
FRLayout<State<T>, String> layout = new FRLayout<>(g);
// layout.setRepulsionMultiplier(2);
// layout.setMaxIterations(20);
layout.setSize(new Dimension(1100, 950)); // sets the initial size of the space
VisualizationViewer<State<T>, String> vv = new VisualizationViewer<>(layout);
vv.setPreferredSize(new Dimension(1280, 1024)); //Sets the viewing area size
vv.getRenderContext().setEdgeLabelTransformer(new ToStringLabeller<String>());
vv.getRenderContext().setVertexLabelTransformer(new ToStringLabeller<State<T>>());
vv.getRenderer().getVertexLabelRenderer().setPosition(Renderer.VertexLabel.Position.AUTO);
// final VisualizationModel<String,Number> visualizationModel =
// new DefaultVisualizationModel<String,Number>(layout, preferredSize);
// this class will provide both label drawing and vertex shapes
VertexLabelAsShapeRenderer<State<T>, String> vlasr = new VertexLabelAsShapeRenderer<>(vv.getRenderContext());
//
// // customize the render context
if ( formater != null ) {
vv.getRenderContext().setVertexLabelTransformer(
new Transformer<State<T>, String>() {
@Override
public String transform(State<T> state) {
return formater.toHtml(state);
}
});
vv.setVertexToolTipTransformer(new Transformer<State<T>, String>() {
@Override
public String transform(State<T> state) {
return formater.toToolTipHtml(state);
}
});
}
vv.getRenderContext().setVertexShapeTransformer(vlasr);
vv.getRenderContext().setVertexLabelRenderer(new DefaultVertexLabelRenderer(Color.RED));
vv.getRenderContext().setEdgeDrawPaintTransformer(new ConstantTransformer(Color.DARK_GRAY));
vv.getRenderContext().setEdgeStrokeTransformer(new ConstantTransformer(new BasicStroke(2.5f)));
// customize the renderer
vv.getRenderer().setVertexRenderer(new GradientVertexRenderer<State<T>, String>(Color.LIGHT_GRAY, Color.WHITE, true));
vv.getRenderer().setVertexLabelRenderer(vlasr);
DefaultModalGraphMouse gm = new DefaultModalGraphMouse();
gm.setMode(ModalGraphMouse.Mode.TRANSFORMING);
vv.setGraphMouse(gm);
vv.addKeyListener(gm.getModeKeyListener());
JFrame frame = new JFrame("Simple Graph View");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().setLayout(new BorderLayout());
frame.getContentPane().add(vv, BorderLayout.CENTER);
frame.getContentPane().add(gm.getModeComboBox(), BorderLayout.SOUTH);
frame.pack();
frame.setVisible(true);
}
}