/*
* (C) Copyright IBM Corp. 2009
*
* LICENSE: Eclipse Public License v1.0
* http://www.eclipse.org/legal/epl-v10.html
*/
package com.ibm.gaiandb.draw;
import java.awt.Graphics2D;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.MouseEvent;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import prefuse.Constants;
import prefuse.Visualization;
import prefuse.action.Action;
import prefuse.action.ActionList;
import prefuse.action.RepaintAction;
import prefuse.action.assignment.ColorAction;
import prefuse.action.assignment.ShapeAction;
import prefuse.action.layout.graph.ForceDirectedLayout;
import prefuse.activity.Activity;
import prefuse.controls.Control;
import prefuse.controls.ControlAdapter;
import prefuse.controls.DragControl;
import prefuse.controls.PanControl;
import prefuse.controls.WheelZoomControl;
import prefuse.controls.ZoomControl;
import prefuse.controls.ZoomToFitControl;
import prefuse.render.DefaultRendererFactory;
import prefuse.render.EdgeRenderer;
import prefuse.render.ShapeRenderer;
import prefuse.util.force.DragForce;
import prefuse.util.force.ForceSimulator;
import prefuse.util.force.NBodyForce;
import prefuse.util.force.SpringForce;
import prefuse.visual.VisualItem;
public class NodeGraph extends Graph {
// Use PROPRIETARY notice if class contains a main() method, otherwise use COPYRIGHT notice.
public static final String COPYRIGHT_NOTICE = "(c) Copyright IBM Corp. 2009";
private static final long serialVersionUID = 8753567782561481785L;
public static final String NAME_SUFFIX = "_NAME";
public static final String NAME_COLUMN = NODE_ID_COLUMN + NAME_SUFFIX;
public static final String EDGE_SOURCE_COLUMN = SOURCE_ID_COLUMN + NAME_SUFFIX;
public static final String EDGE_TARGET_COLUMN = TARGET_ID_COLUMN + NAME_SUFFIX;
public static final int EDGE_THICKNESS = 1;
public static final int EDGE_COLOR = 0xFFCCCCCC;
public static final int SELECTED_EDGE_COLOR = 0xFF000000;
private boolean updating = false;
private String currentHoverItemName = null;
public int getNodeCount() {
return null != data ? data.getNodeCount() : 0;
}
public String getCurrentItemName() {
return currentHoverItemName;
}
private ActionList position = new ActionList(Activity.INFINITY);
private SpringForce springForce = new SpringForce(
1e-5f, SpringForce.DEFAULT_SPRING_LENGTH);
private static final int SPRING_LENGTH_MULTIPLIER = 100;
public NodeGraph(PreparedStatement statement, Object... params) throws SQLException {
super(statement, params);
}
public void beforeUpdate() {
updating = true;
if (null != position) {
position.cancel();
}
}
public void afterUpdate() {
if (null != position) {
m_vis.run("position");
}
updating = false;
}
private class ActionSilencer extends Action {
Action action;
public ActionSilencer(Action action) {
super();
this.action = action;
}
public void run(double frac) {
try {
action.run(frac);
}
catch (Exception e) {
// Ignore it. Silent, remember?
}
}
public void setVisualization(Visualization vis) {
super.setVisualization(vis);
action.setVisualization(vis);
}
}
protected synchronized void prepareVis() {
m_vis.addGraph(GROUP, data);
// LabelRenderer lr = new LabelRenderer(NAME_COLUMN);
// lr.setRoundedCorner(10, 10);
DefaultRendererFactory renderer = new DefaultRendererFactory(
new ShapeRenderer(),
// lr,
new EdgeRenderer() {
public void render(Graphics2D g, VisualItem item) {
if (updating) {
return;
}
if (null != currentHoverItemName &&
(currentHoverItemName.equals(item.getString(EDGE_SOURCE_COLUMN)) ||
currentHoverItemName.equals(item.getString(EDGE_TARGET_COLUMN)))) {
item.setSize(EDGE_THICKNESS * 2);
item.setStrokeColor(SELECTED_EDGE_COLOR);
}
else {
item.setSize(EDGE_THICKNESS);
item.setStrokeColor(EDGE_COLOR);
}
super.render(g, item);
}
}
);
m_vis.setRendererFactory(renderer);
// Set up the drawing actions.
if (null == nodeShapeAction) {
nodeShapeAction = new ShapeAction(NODE_GROUP, Constants.SHAPE_ELLIPSE);
draw.add(nodeShapeAction);
}
if (null == nodeColorAction) {
nodeColorAction = new ColorAction(NODE_GROUP, VisualItem.FILLCOLOR);
draw.add(nodeColorAction);
}
if (null == edgeColorAction) {
edgeColorAction = new ColorAction(EDGE_GROUP, VisualItem.STROKECOLOR, EDGE_COLOR);
draw.add(edgeColorAction);
}
draw.add(new RepaintAction());
m_vis.putAction("draw", draw);
// Set up the positioning actions.
ForceSimulator forces = new ForceSimulator();
forces.addForce(new NBodyForce());
forces.addForce(springForce);
forces.addForce(new DragForce());
position.add(new ActionSilencer(new ForceDirectedLayout(GROUP, forces, false)));
position.add(new ActionSilencer(new RepaintAction()));
m_vis.putAction("position", position);
// Set up movement and zooming for windows and nodes.
addControlListener(new DragControl());
addControlListener(new PanControl());
addControlListener(new ZoomControl());
addControlListener(new WheelZoomControl());
addControlListener(new ZoomToFitControl(Control.MIDDLE_MOUSE_BUTTON));
addControlListener(new ControlAdapter() {
public void itemEntered(VisualItem item, MouseEvent event) {
if (item.isInGroup(NODE_GROUP)) {
try {
currentHoverItemName = item.getString(NAME_COLUMN);
}
catch (IndexOutOfBoundsException e) {
// Ignore it. It means we're in the middle of updating.
}
}
}
public void itemExited(VisualItem item, MouseEvent event) {
currentHoverItemName = null;
}
});
// Centre the graph.
pan(getWidth() / 2, getHeight() / 2);
// Reset the object boundaries whenever the window is resized.
addComponentListener(new ComponentAdapter() {
public void componentResized(ComponentEvent e) {
updateVisualization();
}
});
m_vis.run("position");
updateVis();
}
protected synchronized void updateVis() {
springForce.setMaxValue(SpringForce.SPRING_LENGTH,
(float)(Math.log10(data.getNodeCount()) * SPRING_LENGTH_MULTIPLIER));
m_vis.run("draw");
}
}