// Medusa is a graph viewer which allows interactive editing of networks
// (edges and nodes) and also connects to databases.
//
// Copyright (C) 2006 Sean Hooper
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or (at
// your option) any later version.
//
// This program 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 General
// Public License for more details.
//
// You should have received a copy of the GNU General Public License along
// with this program; if not, write to the
// Free Software Foundation, Inc.,
// 59 Temple Place, Suite 330,
// Boston, MA 02111-1307 USA
package medusa.display;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.event.MouseEvent;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Iterator;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.util.List;
import javax.swing.JOptionPane;
import medusa.*;
import medusa.dataio.DataLoader;
import medusa.georgios.Browser;
import medusa.graph.Edge;
import medusa.graph.Graph;
import medusa.graph.Node;
/**
* Describe class EditableGraphPanel here.
* This class extends BasicGraphPanel and allows mouse interactions,
* and also data manipulation.
*
*
* @author Sean Hooper
* @version 1.0
*/
public class EditableGraphPanel extends BasicGraphPanel {
//Image image=null;
BufferedImage image = null;
Image tempImage = null;
// constructor
/**
* Constructor with settings
* @param stringSettings settings
*/
public EditableGraphPanel(MedusaSettings stringSettings) {
super(stringSettings);
initPopup();
tryImage();
initShow();
//setBackground(Color.grey);
}
/**
* Constructor with default settings
*/
public EditableGraphPanel() {
super();
initPopup();
tryImage();
initShow();
}
private void tryImage() {
try {
setImage();
tempImage = image;
} catch (Exception e) {
}
}
/**
* Sets the default image
* @throws java.io.IOException if default file
*/
public void setImage() throws IOException {
setImage("netview_default.png");
}
/**
* Sets the background image
* @param imageURL path to image
* @throws java.io.IOException if image is not found or cannot be read.
*/
public void setImage(final String imageURL)
throws IOException {
//System.out.println(imageURL);
File imageFile = new File(imageURL);
image = javax.imageio.ImageIO.read(imageFile);
}
/**
*
* @param myImage
* @throws java.lang.InterruptedException
*/
public void setImage(BufferedImage myImage) throws InterruptedException {
image = myImage;
//scaledCopy();
}
public void clearImage() {
image = null;
//System.out.println("image cleared");
}
/* -------------------------------------------------------------
* -more overridden methods of BasicGraphPanel-------------------
* -------------------------------------------------------------
*/
public void drawBackgroundImage(Graphics2D g2d) {
if (image == null) {
return;
}
Dimension d = getPreferredSize();
//System.out.println(d.width+" : "+d.height);
g2d.drawImage(image, 0, 0, d.width, d.height, null);
}
public void paintEdge(Graphics2D g, Edge e) {
if (!showEdges[e.getType() - 1]) {
return;
}
super.paintEdge(g, e);
}
public boolean showBorder = true;
public void setShowBorder(boolean show) {
showBorder = show;
}
public void paintNet(Graphics2D g2d) {
// if we have an image, paint it
//drawBackgroundImage(g2d);
// draw the border
//g2d.setColor(Color.gray);
if (showBorder) {
Rectangle2D.Double border = new Rectangle2D.Double(2, 2, getPanelWidth(), getPanelHeight());
g2d.draw(border);
}
for (Iterator edges = graph.edgesIterator(); edges.hasNext();) {
Edge e = (Edge) edges.next();
int col = e.getType();
if (showEdges[col - 1]) {
paintEdge(g2d, e);
}
}
//make sure confidence is restored
g2d.setComposite(makeComposite(1.0f));
for (Iterator it = graph.nodesIterator(); it.hasNext();) {
Node node = (Node) it.next();
paintNode(g2d, node);
}
//PaintTools.paintPath(g2d,10);
}
public void saveImage(String path, int param) {
setShowBorder(false);
super.saveImage(path, param);
setShowBorder(true);
}
/**
* Paints the component
* @param g current graphics
*/
public synchronized void paintComponent(Graphics g) {
Graphics2D g2d = prePaint(g);
// if we have an image, paint it
drawBackgroundImage(g2d);
if (hideWhenMove) {
if ((!running) & (pick != null)) {
paintVisibleNet(g2d);
} else {
paintNet(g2d);
}
} else {
paintNet(g2d);
}
//paintNet(g2d);
//markNode(g2d, marked);
// for selection boxes
drawBox(g2d);
if (drawTempLine) {
float[] dashPattern = {2, 3, 2, 3};
g2d.setStroke(new BasicStroke(1, BasicStroke.CAP_BUTT,
BasicStroke.JOIN_MITER, 10,
dashPattern, 0));
g2d.drawLine(startx, starty, endx, endy);
}
g2d.setStroke(new BasicStroke(1));
}
public void paintVisibleNet(Graphics2D g2d) {
// draw the border
//g2d.setColor(Color.gray);
if (showBorder) {
Rectangle2D.Double border = new Rectangle2D.Double(2, 2, getPanelWidth(), getPanelHeight());
g2d.draw(border);
}
for (Iterator edges = getVisibleGraph().edgesIterator(); edges.hasNext();) {
Edge e = (Edge) edges.next();
int col = e.getType();
if (showEdges[col - 1]) {
paintEdge(g2d, e);
}
}
//make sure confidence is restored
g2d.setComposite(makeComposite(1.0f));
for (Iterator it = graph.nodesIterator(); it.hasNext();) {
Node node = (Node) it.next();
paintNode(g2d, node);
}
//PaintTools.paintPath(g2d,10);
}
//public void loadingMessage(){
// Graphics2d g2d =
protected void drawBox(Graphics2D g2d) {
if (getCurrentRect() != null) {
//Draw a rectangle on top of the image.
g2d.setXORMode(Color.red); //Color of line varies
//depending on image colors
float[] dashPattern = {2, 3, 2, 3};
g2d.setStroke(new BasicStroke(1, BasicStroke.CAP_BUTT,
BasicStroke.JOIN_MITER, 10,
dashPattern, 0));
g2d.drawRect(rectToDraw.x, rectToDraw.y,
rectToDraw.width - 1, rectToDraw.height - 1);
}
}
protected boolean showName = true;
/**
* Switches between showing node name and annotation
* @param b true if names are to be shown, false if annotation
*/
public void setShowName(boolean b) {
showName = b;
showAnnotation = (!b);
}
/**********************
* // handle editing events (right mouse button)
************************/
private void handleRightMouseDragged(MouseEvent e) {
if ((e.getModifiers() & MouseEvent.BUTTON3_MASK) != 0) {
// set line drawing to true, and repaint
drawTempLine = true;
endx = e.getX();
endy = e.getY();
repaint();
}
e.consume();
}
public void mouseDragged(MouseEvent e) {
handleLeftMouseDragged(e);
handleRightMouseDragged(e);
}
public void handleReleaseRightButton(MouseEvent e) {
if (e.getButton() != MouseEvent.BUTTON3) {
return;
}
removeMouseMotionListener(this);
//int i=getClosest(e);
Node node = getClosest(e);
if (node != null) {
// prompt for new node
temp2 = node;
} else {
temp2 = new Node("unnamed", e.getX(), e.getY());
}
drawTempLine = false;
endx = e.getX();
endy = e.getY();
if (temp1 != temp2) {
//System.out.println(temp1+" "+temp2);
addEdge();
repaint();
temp1 = null;
temp2 = null;
} else {
//System.out.println(temp1.getLabel());
showPopup(e);
}
//System.out.println(temp1+"\n ---> "+temp2);
}
public void mouseReleased(MouseEvent e) {
handleReleaseLeftButton(e);
handleReleaseRightButton(e);
}
private void handlePressRightButton(MouseEvent e) {
if (e.getButton() == MouseEvent.BUTTON3) {
addMouseMotionListener(this);
Node node = getClosest(e);
//int index=getClosest(e);
if (node != null) {
temp1 = node;
//System.out.println("dragging from "+nodeArray[index]);
startx = (int) temp1.getX();
starty = (int) temp1.getY();
} else {
startx = e.getX();
starty = e.getY();
temp1 = new Node("unnamed", startx, starty);
}
e.consume();
}
}
public void mousePressed(MouseEvent e) {
handlePressLeftButton(e);
handlePressRightButton(e);
} // the edge dialog
Frame f = new Frame();
protected void addEdge() {
//Frame f = new Frame();
//System.out.println(temp1+" "+temp2);
Edge e = EdgeDialog.showDialog(f, null, temp1, temp2, getStringSettings());
if (e != null) {
temp1.setLabel(e.getFromName());
temp2.setLabel(e.getToName());
graph.addEdge(e);
graph.setNode(temp1);
graph.setNode(temp2);
updateNodes();
}
} // to add edges, we need startx, starty, endx and endy. When complete,
// open the dialog to specify the params
int startx;
int starty;
int endx;
int endy;
boolean drawTempLine = false;
Node temp1 = null;
Node temp2 = null; // an array to remember which edges to show/hide
boolean[] showEdges;
public void initShow() {
final int max = 40;
showEdges = new boolean[max];
for (int i = 0; i < max; i++) {
showEdges[i] = true;
}
}
/**
* Shows the interaction type i
* @param i interaction type to show
* @param b true: paint interaction type. false: hide interaction type
*/
public void setShowEdge(int i, boolean b) {
showEdges[i] = b;
}
public void setHideEdge(int i, boolean b) {
showEdges[i] = (!b);
}
int border = 10;
/**
* Sets the shape for fixed nodes
* @param shape 0-3: implemented shapes in PaintTools
*/
public void setShape(int shape) {
for (Iterator it = graph.nodesIterator(); it.hasNext();) {
Node node = (Node) it.next();
if (node.isFixed()) {
node.setShape(shape);
}
}
}
/* popup!!!!!
*
*/
javax.swing.JPopupMenu popup;
javax.swing.JMenuItem removeItem;
javax.swing.JMenuItem editColorItem;
javax.swing.JMenuItem editShapeItem;
javax.swing.JMenuItem setAnnotationItem;
javax.swing.JMenuItem getPositionItem;
javax.swing.JMenu URLItem;
javax.swing.JMenuItem setURLItem;
javax.swing.JMenuItem setClusterItem;
javax.swing.JMenuItem gotoURLItem;
// show a popup in certain cases
private void initPopup() {
//System.out.println("initializing popup");
popup = new javax.swing.JPopupMenu("Edit data");
removeItem = new javax.swing.JMenuItem("Delete");
editColorItem = new javax.swing.JMenuItem("Color");
editShapeItem = new javax.swing.JMenuItem("Shape");
setAnnotationItem = new javax.swing.JMenuItem("Annotation");
URLItem = new javax.swing.JMenu("URL");
gotoURLItem = new javax.swing.JMenuItem("Go to page");
setURLItem = new javax.swing.JMenuItem("Edit URL");
setClusterItem = new javax.swing.JMenuItem("Edit Predefined Cluster");
getPositionItem = new javax.swing.JMenuItem("Position");
removeItem.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent e) {
if (temp1 != null) {
//System.out.println("removing node "+temp1.getLabel());
removeEdgeByLabel(temp1.getLabel());
temp1 = null;
temp2 = null;
repaint();
} else {
System.out.println("node is null, for some strange reason");
}
}
});
editColorItem.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent e) {
Color newColor = javax.swing.JColorChooser.showDialog(getRootPane(),
"Choose node color",
temp1.getColor());
if (newColor != null) {
temp1.setColor(newColor);
}
repaint();
}
});
editShapeItem.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent e) {
temp1.setShape(chooseShape());
repaint();
}
});
setAnnotationItem.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent e) {
setAnnotation(temp1);
}
});
setURLItem.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent e) {
setURL(temp1);
}
});
setClusterItem.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent e) {
setPredefinedCluster(temp1);
}
});
gotoURLItem.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent e) {
if (temp1.getURL().startsWith("http://")) {
Browser.openURL(temp1.getURL());
}
}
});
getPositionItem.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent e) {
getPosition(temp1);
}
});
popup.add(removeItem);
popup.addSeparator();
popup.add(editColorItem);
popup.add(editShapeItem);
popup.add(setAnnotationItem);
popup.add(URLItem);
URLItem.add(setURLItem);
popup.add(setClusterItem);
URLItem.add(gotoURLItem);
popup.add(getPositionItem);
}
private void getPosition(Node temp) {
javax.swing.JOptionPane.showMessageDialog(MedusaSimplerFrame.stringletPanel,
"x: " + temp.getX() + " y:" + temp.getY());
}
private void setAnnotation(Node temp) {
String s = (String) javax.swing.JOptionPane.showInputDialog("View or edit node annotation:\n",
temp.getAnnotation());
if ((s != null) && (s.length() > 0)) {
temp.setAnnotation(s);
}
}
private void setURL(Node temp) {
String s = (String) javax.swing.JOptionPane.showInputDialog("View or edit node URL:\n",
temp.getURL());
if ((s != null) && (s.length() > 0)) {
if (!s.startsWith("http://")) {
JOptionPane.showMessageDialog(MedusaSimplerFrame.stringletPanel, "URL does not start with http://");
} else {
temp.setURL(s);
}
}
}
private void setPredefinedCluster(Node temp) {
String s = (String) javax.swing.JOptionPane.showInputDialog("View or edit node predefined cluster:\n",
temp.getCLuster());
if ((s != null) && (s.matches("[0-9]+"))) {
if ((Integer.parseInt(s) >= 1) || (Integer.parseInt(s) == -1)) {
temp.setCluster(s);
} else {
JOptionPane.showMessageDialog(MedusaSimplerFrame.stringletPanel, "Cluster takes a positive value >1 or -1 for no cluster");
}
}
}
private int chooseShape() {
Object[] shapes = {"circle", "rectangle", "triangle", "diamond"};
int s = javax.swing.JOptionPane.showOptionDialog(this,
"Choose a node shape",
"Shape",
javax.swing.JOptionPane.YES_NO_CANCEL_OPTION,
javax.swing.JOptionPane.QUESTION_MESSAGE,
null,
shapes,
"circle");
return s;
}
private void showPopup(MouseEvent e) {
popup.show(e.getComponent(), e.getX(), e.getY());
e.consume();
}
/*
* manipulate data
*
*/
public java.util.ArrayList getFixed() {
return graph.getFixed();
}
public void copyNodeSettings(Graph g) {
graph.copyNodeSettings(g);
}
public void removeEdgeByLabel(String label) {
//System.out.println("removing "+label);
graph.removeEdgeByLabel(label);
}
public void removeFixedNodes() {
graph.removeFixed();
}
public void crop(double confidence) {
graph.cropEdges(confidence);
calculateEdgeLength();
}
/* A regular expression search, for finding nodes matching a
* string. The string should be sent from the front-end.
*/
/* Set a method of marking nodes that users search for
* by displaying for instance an arrow
*/
public void markNode(java.awt.Graphics2D g2d, Node markedNode) {
if (markedNode == null) {
return;
}
// start by just drawing an arrow
// from ref point 0,0
int refX = (int) (getPanelWidth() / 2);
int refY = (int) (getPanelHeight() / 2);
double r45 = Math.PI / 7.0;
double deltaLength = 15.0;
double headLength = 13.0;
// get theta
double x = markedNode.getX();
double y = markedNode.getY();
double deltaX = (x - refX);
double deltaY = -(y - refY);
double theta = Math.atan(deltaY / deltaX);
if (deltaX < 0.0) {
theta += Math.PI; // get x,y for the head point
}
int xh = (int) (x - deltaLength * Math.cos(theta));
int yh = (int) (y + deltaLength * Math.sin(theta));
// get clockwise shoulder point
int xc = (int) (xh - headLength * Math.cos(theta - r45));
int yc = (int) (yh + headLength * Math.sin(theta - r45));
// get anti-clockwise shoulder point
int xa = (int) (xh - headLength * Math.cos(theta + r45));
int ya = (int) (yh + headLength * Math.sin(theta + r45));
// the shadow
int shad = 3;
// build a polygon from this
int[] xpoints = {xc, xh, xa};
int[] ypoints = {yc, yh, ya};
int[] shadowX = {xc + shad, xh + shad, xa + shad};
int[] shadowY = {yc + shad, yh + shad, ya + shad};
int npoints = 3;
// draw it
//g2d.setColor(Color.magenta);
g2d.setColor(Color.black);
g2d.fillPolygon(shadowX, shadowY, npoints);
g2d.setColor(Color.orange);
g2d.fillPolygon(xpoints, ypoints, npoints);
g2d.setColor(Color.black);
}
public int selectNodeByRegExp(final String regexp, boolean label) {
int matches = 0;
Pattern labelPattern = Pattern.compile(regexp);
Matcher matcher;
// loop through and fix nodes that match the expression
for (Iterator it = graph.nodesIterator(); it.hasNext();) {
Node node = (Node) it.next();
String toMatch = label ? node.getLabel() : node.getAnnotation();
matcher = labelPattern.matcher(toMatch);
if (matcher.find()) {
node.setFixed(true);
matches++;
}
}
return matches;
}
/**
* Reads a file of node names and selected those nodes in the graph.
* @param fileName
* @throws java.io.IOException
* @return
*/
public int selectNodeFromFile(final String fileName) throws IOException {
int matches = 0;
String inLine;
File loadFile = new File(fileName);
BufferedReader in = new BufferedReader(new InputStreamReader(new FileInputStream(loadFile)));
while ((inLine = in.readLine()) != null) {
for (Iterator it = graph.nodesIterator(); it.hasNext();) {
Node node = (Node) it.next();
if (node.getLabel().compareTo(inLine) == 0) {
matches++;
node.setFixed(true);
continue;
}
}
}
in.close();
return matches;
}
public void manipulateColor(int a, int b, boolean doSwitch) {
for (Iterator it = graph.nodesIterator(); it.hasNext();) {
Node node = (Node) it.next();
if (node.isFixed()) {
node.manipulateColorElement(a, b, doSwitch);
}
}
}
public void addGradientX(int channel) {
int value;
for (Iterator it = graph.nodesIterator(); it.hasNext();) {
Node node = (Node) it.next();
if (node.isFixed()) {
value = (int) (node.getX() / getPanelWidth() * 255.0);
//System.out.println(node.getLabel()+" "+value);
node.manipulateChannel(channel, value);
}
}
}
public void addGradientY(int channel) {
int value;
for (Iterator it = graph.nodesIterator(); it.hasNext();) {
Node node = (Node) it.next();
if (node.isFixed()) {
value = (int) (node.getY() / getPanelWidth() * 255.0);
//System.out.println(node.getLabel()+" "+value);
node.manipulateChannel(channel, value);
}
}
}
public void clearGraph() {
graph.clear();
updateNodes();
} //Timer loadTimer;
//public void loadGraphThread(){
// loadTimer = new Timer(200,loadGraphThreadActionEvent);
DataLoader dl = new DataLoader(getPanelWidth(), getPanelHeight());
public void loadGraph(String fileName) throws IOException, DataFormatException {
graph = dl.load(fileName);
updateNodes();
}
public void saveGraph(String fileName) throws IOException {
dl.save(graph, fileName, scale);
updateNodes();
}
public void writePajek(String fileName) throws IOException {
dl.saveAsPajek(graph, fileName);
}
public void writeArena3D(String fileName) throws IOException {
dl.saveAsArena3D(graph, fileName);
}
public void writeCytoscape(String fileName) throws IOException {
dl.saveAsCytoscape(graph, fileName);
}
public void writeGraphViz(String fileName) throws IOException {
dl.saveAsGraphViz(graph, fileName);
}
public void writeBiolayout(String fileName) throws IOException {
dl.saveAsBiolayout(graph, fileName);
}
public void writePS(String fileName) throws IOException {
dl.saveAsPS(graph, fileName, getStringSettings(), nodeSize, fontSize);
//updateNodes();
}
public void writeEPS(String fileName) throws IOException {
dl.saveAsEPS(graph, fileName, getStringSettings(), nodeSize, fontSize);
//updateNodes();
}
/* Data manipulation tools
*/
public void appendGraph(String fileName) throws IOException, DataFormatException {
Graph temp = dl.load(fileName);
graph.addGraph(temp);
copyNodeSettings(temp);
calculateEdgeLength();
//System.out.println(graph.report());
updateNodes();
}
public void subtractGraph(String fileName) throws IOException, DataFormatException {
Graph temp = dl.load(fileName);
graph.subtractGraph(temp);
copyNodeSettings(temp);
calculateEdgeLength();
//System.out.println(graph.report());
updateNodes();
}
public void copyGraphSettings(String fileName) throws IOException, DataFormatException {
Graph temp = dl.load(fileName);
//graph.addGraph(temp);
copyNodeSettings(temp);
//calculateEdgeLength();
//System.out.println(graph.report());
updateNodes();
}
public void addGraph(Graph g) {
if (g == null) {
return;
}
g.rescaleNodes(600);
graph.addGraph(g);
copyNodeSettings(g);
}
public void growSelection() {
// get a temp graph of fixed nodes
graph.growSelection();
}
//
// public void shrinkGraph(){
// graph.shrinkGraph()
// }
public void alignNodes(int align) {
List nodes = getFixed();
// find the left-most node
int y = 0;
Node node = getExtremeNode(align, nodes);
if (node==null){
//System.out.println("null! (EditableGraphPanel)");
return;
}
//System.out.println("not null! (EditableGraphPanel) "+node.getLabel());
for (int i = 0; i < nodes.size(); i++) {
Node n = nodes.get(i);
if ((align == EXTREME_LEFT) || (align == EXTREME_RIGHT)) {
n.setY(node.getY());
}
if ((align == EXTREME_TOP) || (align == EXTREME_BOTTOM)) {
n.setX(node.getX());
}
}
}
public static int EXTREME_LEFT = 9001;
public static int EXTREME_RIGHT = 9002;
public static int EXTREME_TOP = 9003;
public static int EXTREME_BOTTOM = 9004;
public Node getExtremeNode(int extreme, List nodes) {
double leftValue = Double.MAX_VALUE;
double topValue = Double.MAX_VALUE;
double rightValue = 0.0;
double bottomValue = 0.0;
int left = 0;
int right = 0;
int top = 0;
int bottom = 0;
for (int i = 0; i < nodes.size(); i++) {
Node n = nodes.get(i);
if (n.getX() < leftValue) {
leftValue = n.getX();
left = i;
}
if (n.getX() > rightValue) {
rightValue = n.getX();
right = i;
}
if (n.getY() < topValue) {
topValue = n.getY();
top = i;
}
if (n.getY() > bottomValue) {
bottomValue = n.getY();
bottom = i;
}
}
if (extreme == EXTREME_LEFT) {
return nodes.get(left);
}
if (extreme == EXTREME_RIGHT) {
return nodes.get(right);
}
if (extreme == EXTREME_TOP) {
return nodes.get(top);
}
if (extreme == EXTREME_BOTTOM) {
return nodes.get(bottom);
}
return null;
}
}
Ads help maintain this website.