// 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.Frame;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.MediaTracker;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
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.ArrayList;
import java.util.Iterator;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.swing.JColorChooser;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPopupMenu;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import javax.imageio.ImageIO;
import medusa.*;
import medusa.dataio.DataLoader;
import medusa.graph.Edge;
import medusa.graph.Graph;
import medusa.graph.Node;
/**
* Describe class DisplayPanel here.
* This class extends BasicGraphPanel and allows mouse interactions,
* and also data manipulation.
*
* @author Sean Hooper
* @version 1.0
*/
public class DisplayPanel extends BasicGraphPanel {
//Image image=null;
BufferedImage image=null;
Image tempImage=null;
// constructor
/**
* Constructor with settings
* @param stringSettings settings
*/
public DisplayPanel(MedusaSettings stringSettings){
super(stringSettings);
initPopup();
tryImage();
initShow();
//setBackground(Color.grey);
}
/**
* Constructor with default settings
*/
public DisplayPanel(){
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;
g2d.drawImage(image, 0,0, getPanelWidth(), getPanelHeight(), null);
}
public void paintEdge(Graphics2D g, Edge e){
if (!showEdges[e.getType()-1])
return;
// return;
Node from =getGraph().getNode(e.getFromName());
Node to = getGraph().getNode(e.n2);
int x1 = (int)from.getX();
int y1 = (int)from.getY();
int x2 = (int)to.getX();
int y2 = (int)to.getY();
// handle confidence
if (showConfidence){
if (alpha)
g.setComposite(makeComposite(e.getConf()));
else
g.setStroke(getStroke(e.getConf()) );
}
g.setPaint(basicEdgeColor);
//if (e.visible)
//g.setPaint(Color.red);
if (pretty){
g.setPaint(getColor( new Integer(e.getType()) ));
//System.out.println(stringSettings.getLabel(e.color));
PaintTools.paintPath(g, x1, y1,
x2, y2, e.getOrientation(), 0.3, arrow);
} else{
g.drawLine(x1,y1,x2,y2);
}
}
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 = (Graphics2D) g;
g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setStroke(new BasicStroke(1));
clear(g2d);
//paintBackground(g2d);clear(g2d);
if (hideWhenMove){
if ((!running)&(pick!=null)){
//System.out.println("moving few");
//g2d.drawString("weng",100,100);
paintPick(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 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);
}
public void paintNode(Graphics2D g, Node n){
g.setStroke(new BasicStroke(1));
g.setPaint(n.getColor());
int x=(int) n.getX() - correct;
int y=(int) n.getY() - correct;
Shape shape = PaintTools.getShape(n.getShape(),x,y,nodeSize);
g.fill(shape);
g.setPaint(Color.black);
if (n.isFixed())
g.setPaint(Color.yellow);
g.draw(shape);
g.setPaint(fontColor);
g.setFont(nodeFont);
if (label){
if (showName) {
g.drawString(n.getLabel(),x-2,y-2);
} else {
g.drawString(n.getAnnotation(),x-2,y-2);
}
}
}
/**********************
* // 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=20;
showEdges=new boolean[max];
for (int i=0; ii
* @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;
// 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");
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);
}
} );
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(getPositionItem);
}
private void getPosition(Node temp){
javax.swing.JOptionPane.showMessageDialog(this,
"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 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;
}
public void updateStringSettings(MedusaSettings ss){
setStringSettings(ss);
// this.stringSettings=ss;
}
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.
*/
/**
* Finds the node matching the regular expression
* @param expression pattern to match
* @return true if nodes were found, false if no nodes matched the pattern
*/
public boolean findLabel(String expression){
//marked = null;
Pattern labelPattern = Pattern.compile(expression);
Matcher matcher;
// if selection is "", remove mark
if (expression.compareTo("")==0){
return false;
}
// Else, look for a match
for(Iterator it = graph.nodesIterator(); it.hasNext();) {
Node node = (Node)it.next();
matcher = labelPattern.matcher(node.getLabel());
node.setFixed(false);
if (matcher.find()){
//marked = node;
node.setFixed(true);
//return node;
}
}
return true;
}
/* 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){
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();
matcher = labelPattern.matcher(node.getLabel());
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 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 addGraph(Graph g){
if (g==null)
return;
g.rescaleNodes(600);
graph.addGraph(g);
copyNodeSettings(g);
}
}
Ads help maintain this website.