package att.grappa;
import java.awt.*;
import java.awt.event.*;
import java.util.*;
/**
* The canvas used for drawing graphs. Its constructor is called
* automatically by the DrawPane
constructor.
*
* @version 1.1, 21 Jan 1998; Copyright 1996, 1997, 1998 by AT&T Corp.
* @author John Mocenigo, Research @ AT&T Labs
*/
public class DrawCanvas extends Canvas
{
//private boolean imageFlag = false;
DrawPane pane = null;
private Image osImage = null;
private Graphics osGraphics = null;
private Dimension osSize = null;
private Rectangle osDrawn = null;
private static Dimension minSize = new Dimension(500,500);
private Dimension prefSize = null;
//added by Erol
private Point startArrowPos,endArrowPos;
//Erol
/*
* @param pane the parent pane
* @param prefSize the preferred size of the canvas
*/
DrawCanvas(DrawPane pane, Dimension prefSize) {
super();
this.pane = pane;
this.prefSize = new Dimension(prefSize);
Mouser mouser = new Mouser();
addMouseListener(mouser);
addMouseMotionListener(mouser);
}
public void update(Graphics gr) {
paint(gr);
}
public void paint(Graphics gr) {
Dimension sz = getSize();
if(osImage == null || osSize.width != sz.width || osSize.height != sz.height) {
osSize = new Dimension(sz);
osImage = createImage(sz.width,sz.height);
osGraphics = osImage.getGraphics();
paintOS(null);
//setImageFlag(true);
}
gr.drawImage(osImage,0,0,null);
}
/**
* Get the off-screen image used for double buffering.
*
* @return the off-screen image
*/
public Image getOSImage() {
return osImage;
}
/**
* Reset the off-screen image by setting it to null, a new image will
* automatically be created the next time paint
is called.
*/
public void resetOSImage() {
osImage = null;
}
/**
* Get the Graphics
used by the off-screen image
*
* @return the off-screen image Graphics
*/
public Graphics getOSGraphics() {
return osGraphics;
}
/*
*public void paintElement(Element elem) {
*elem.getDrawObject().draw(null,getDrawPane());
*}
*/
/**
* Writes a PostScript representation
* of the canvas to the supplied PrintWriter.
*/
public void paintPostScript(java.io.PrintWriter pw) {
PSGr psgr = new PSGr((java.io.Writer)pw,getGraphics(),getBounds());
psgr.setBackground(getGraph().getDrawObject().getGC().getBackground());
psgr.setColor(getGraph().getDrawObject().getGC().getBackground());
Dimension sz = getSize();
psgr.fillRect(0,0,sz.width,sz.height);
getDrawPane().doBackground(psgr);
Enumeration elems = getDrawPane().getDrawGraph().elements();
Element elem = null;
Graphics saveGraphics = osGraphics;
osGraphics = psgr;
while(elems.hasMoreElements()) {
elem = (Element)elems.nextElement();
elem.getDrawObject().draw(null,getDrawPane());
}
psgr.showpage();
osGraphics = saveGraphics;
}
private void paintOS(Rectangle cliprect) {
//if(cliprect != null) {
//cliprect = new Rectangle(cliprect);
//cliprect.grow(1,1);
//}
osGraphics.setColor(getGraph().getDrawObject().getGC().getBackground());
osGraphics.setClip(cliprect);
if(cliprect == null) {
Dimension sz = getSize();
osGraphics.fillRect(0,0,sz.width,sz.height);
//cliprect = new Rectangle(0,0,sz.width,sz.height);
} else {
osGraphics.fillRect(cliprect.x,cliprect.y,cliprect.width,cliprect.height);
}
getDrawPane().doBackground(osGraphics);
Enumeration elems = getDrawPane().getDrawGraph().elements();
Element elem = null;
while(elems.hasMoreElements()) {
elem = (Element)elems.nextElement();
if(cliprect == null || cliprect.intersects(elem.getDrawObject().getPeerFor(getDrawPane()).getBounds())) {
elem.getDrawObject().draw(null,getDrawPane());
}
}
}
/**
* Redraws the graph (thereby erasing any spurious info).
*/
public void erase(Graphics gr, Rectangle cliprect) {
Dimension sz = getSize();
if(osImage == null || osSize.width != sz.width || osSize.height != sz.height) {
osSize = new Dimension(sz);
osImage = createImage(sz.width,sz.height);
osGraphics = osImage.getGraphics();
paintOS(null);
} else {
paintOS(cliprect);
}
if(gr == null) {
gr = getGraphics();
}
gr.drawImage(osImage,0,0,this);
}
/**
* Clear the canvas (and off-screen image) by filling with the background
* color of the graph.
*/
public void clear() {
Dimension curSize = getSize();
Graphics gr = getGraphics();
if(gr != null) {
Color bkgd = getGraph().getDrawObject().getGC().getBackground();
gr.setColor(bkgd);
gr.fillRect(0,0,curSize.width,curSize.height);
if(osImage != null) {
//osGraphics.setColor(bkgd);
//osGraphics.fillRect(0,0,osSize.width,osSize.height);
resetOSImage();
}
}
}
public Dimension getMinimumSize() {
return minSize;
}
public void setMinimumSize(Dimension d) {
setMinimumSize(d.width,d.height);
}
public void setMinimumSize(int w, int h) {
minSize.setSize(w,h);
}
public Dimension getPreferredSize() {
return prefSize;
}
/**
* Get the DrawPane
containing this canvas.
*
* @return the containing pane.
*/
public DrawPane getDrawPane() {
return pane;
}
/**
* Get the Graph
using this canvas.
*
* @return the graph using this canvas
*/
public Graph getGraph() {
return getDrawPane().getGraph();
}
public void setSize(Dimension sz) {
setSize(sz.width,sz.height);
}
public void setSize(int w, int h) {
if(w < minSize.width) w = minSize.width;
if(h < minSize.height) h = minSize.height;
prefSize.setSize(w,h);
super.setSize(w,h);
}
//public void setImageFlag(boolean mode) {
// imageFlag = mode;
//}
//public boolean getImageFlag() {
// return imageFlag;
//}
/*
* Mouse behavior:
*
* Button 1 (un-modified) = selection
* Button 3 (un-modified) or just META key = pop-up menu
* Shift Button 1 = create (if not coincident with an existing item)
* Ctrl Button 1 = delete
*
* Button down starts process, button up completes it (when valid).
*/
class Mouser extends MouseAdapter implements MouseMotionListener {
// mouse down/up info
int evtX = 0;
int evtY = 0;
Point dragPt = null;
Point evtPt = null;
Element evtElem = null;
Element delElem = null;
final int BUTTON1_MASK = 0; // needed for a bug in some JVMs
//added by Erol
Point startArrowPos,endArrowPos,passedPoint;
Element passedElem;
extraUtils myUtil;
//Erol
public void mousePressed(MouseEvent evt) {
int x = evt.getX();
int y = evt.getY();
evtX = x;
evtY = y;
evtPt = new Point(x,y);
dragPt = null;
evtElem = getDrawPane().findContainingElement(evtPt);
//Erol
System.out.println("Mouse pressed: "+evtPt);
myUtil = new extraUtils(getDrawPane(),evtPt);
//Erol
processBlock: if(evtElem != null) {
//Added by Erol
startArrowPos = null;
passedElem = null;
passedPoint = evtPt;
//Erol
System.out.println("start drag session");
int evtMod = evt.getModifiers();
if(
evtMod == BUTTON1_MASK ||
evtMod == InputEvent.BUTTON1_MASK
) {
if(!getGraph().isSelectable()) break processBlock;
highlightSelect();
} else if(
evtMod == (BUTTON1_MASK|InputEvent.CTRL_MASK)
||
evtMod == (InputEvent.BUTTON1_MASK|InputEvent.CTRL_MASK)
) {
if(!getGraph().isEditable()) break processBlock;
// highlight for delete
delElem = evtElem;
highlightDelete(delElem,true);
} else if(evtMod == InputEvent.BUTTON3_MASK) {
if(!getGraph().isMenuable()) break processBlock;
highlightSelect();
// do pop-up menu here
}
}
// no wrap up
}
public void mouseReleased(MouseEvent evt) {
int x = evt.getX();
int y = evt.getY();
Point pt = new Point(x,y);
Element elem = null;
System.out.println("Mouse Released !!!");
if(x == evtX && y == evtY) {
elem = evtElem;
} else {
elem = getDrawPane().findContainingElement(pt);
}
int evtMod = evt.getModifiers();
processBlock: if(
evtMod == BUTTON1_MASK
||
evtMod == InputEvent.BUTTON1_MASK
) {
if(!getGraph().isSelectable()) break processBlock;
if(elem != null && evtElem == elem) {
// select the element
if(elem.getAppObject() != null) elem.getAppObject().selected(evt,pt);
} else {
if(getGraph().getCurrent() != null) {
getGraph().setCurrent(null).getDrawObject().highlightOff(DrawObject.SELECTION);
}
}
} else if(evtMod == InputEvent.BUTTON3_MASK) {
if(elem != null && elem == evtElem) {
// pop-down menu here
if(getGraph().isMenuable()) {
if(elem.getAppObject() != null) elem.getAppObject().properties(evt,pt);
}
}
if(getGraph().getCurrent() != null) {
getGraph().setCurrent(null).getDrawObject().highlightOff(DrawObject.SELECTION);
}
} else if(
evtMod == (BUTTON1_MASK|InputEvent.CTRL_MASK)
||
evtMod == (InputEvent.BUTTON1_MASK|InputEvent.CTRL_MASK)
) {
if(getGraph().getCurrent() != null) {
getGraph().setCurrent(null).getDrawObject().highlightOff(DrawObject.SELECTION);
}
if(!getGraph().isEditable()) break processBlock;
if(elem != null && evtElem == elem) {
// do delete
doDelete(delElem);
delElem = null;
}
} else if(
evtMod == (BUTTON1_MASK|InputEvent.SHIFT_MASK)
||
evtMod == (InputEvent.BUTTON1_MASK|InputEvent.SHIFT_MASK)
) {
System.out.println("Mouse released(shift)!!!");
if(getGraph().getCurrent() != null) {
getGraph().setCurrent(null).getDrawObject().highlightOff(DrawObject.SELECTION);
}
if(!getGraph().isEditable()) break processBlock;
if(dragPt != null) {
rubberLine(evtX,evtY,dragPt.x,dragPt.y);
dragPt = null;
}
if(elem == null && (evtElem == null || !evtElem.isNode())) {
// create a node
Point cpt = getDrawPane().canonXY(pt.x,pt.y);
Attribute attr = new Attribute("pos",cpt.x + "," + cpt.y);
Vector attrs = new Vector();
attrs.addElement(attr);
attr = getGraph().getNodeAttribute("label");
if(attr == null || attr.getValue().equals("\\N")) {
attr = new Attribute("label","Node" + getGraph().getId(Grappa.NODE));
attrs.addElement(attr);
}
try {
elem = getGraph().createElement(Grappa.NODE,null,attrs);
} catch(InstantiationException inex) {
Grappa.displayException(inex);
break processBlock;
}
elem.getDrawObject().setBounds();
elem.getDrawObject().draw();
} else if(elem != null && evtElem != null && evtElem != elem && evtElem.isNode()) {
if(elem.isNode()) {
//Added by Erol
Element []ports = myUtil.drawPortNode(startArrowPos,endArrowPos,
"circle",evtElem,elem);
//Erol
// create an Edge
Vector info = new Vector(5);
info.addElement(elem); //tail
info.addElement(null); // tailPort (not available yet)
info.addElement(evtElem); //head
info.addElement(null); // headPort (not available yet)
info.addElement(null); // key
//Point hpt = ((DrawNode)evtElem.getDrawObject()).getPosition();
//Point tpt = ((DrawNode)elem.getDrawObject()).getPosition();
//Deleted by Erol
//Point hpt = getDrawPane().canonXY(evtPt.x,evtPt.y);
//Point tpt = getDrawPane().canonXY(pt.x,pt.y);
//Added by Erol
Point hpt = getDrawPane().canonXY(startArrowPos.x,startArrowPos.y);
Point tpt = getDrawPane().canonXY(endArrowPos.x,endArrowPos.y);
Point mid1 = new Point(hpt.x+(int)Math.round((double)(tpt.x - hpt.x)/3.0),hpt.y+(int)Math.round((double)(tpt.y - hpt.y)/3.0));
Point mid2 = new Point(hpt.x+(int)Math.round(2.0*(double)(tpt.x - hpt.x)/3.0),hpt.y+(int)Math.round(2.0*(double)(tpt.y - hpt.y)/3.0));
Point mid3 = new Point(hpt.x+(int)Math.round(0.98*(double)(tpt.x - hpt.x)),hpt.y+(int)Math.round(0.98*(double)(tpt.y - hpt.y)));
String pos = null;
if(getGraph().isDirected()) {
pos = "e," + tpt.x + "," + tpt.y + " " + hpt.x + "," + hpt.y + " " + mid1.x + "," + mid1.y + " " + mid2.x + "," + mid2.y + " " + mid3.x + "," + mid3.y;
} else {
pos = hpt.x + "," + hpt.y + " " + mid1.x + "," + mid1.y + " " + mid2.x + "," + mid2.y + " " + mid3.x + "," + mid3.y + " " + tpt.x + "," + tpt.y;
}
Attribute attr = new Attribute("pos",pos);
Vector attrs = new Vector();
attrs.addElement(attr);
try {
elem = getGraph().createElement(Grappa.EDGE,info,attrs);
} catch(InstantiationException inex) {
Grappa.displayException(inex);
break processBlock;
}
elem.getDrawObject().setBounds();
elem.getDrawObject().draw();
//Added by Erol
((Edge)elem).setTerminals(startArrowPos,endArrowPos);
((Edge)elem).setTailPort((Node)ports[0]);
((Edge)elem).setHeadPort((Node)ports[1]);
//Erol
}
}
} else {
// ignore mixed signals
if(getGraph().getCurrent() != null) {
getGraph().setCurrent(null).getDrawObject().highlightOff(DrawObject.SELECTION);
}
}
if(delElem != null) {
highlightDelete(delElem,false);
delElem = null;
}
}
// TODO: evtElem == null and mouseDrag, then rubberband and on mouseUp, if
// rectangle contains elements, then create subGraph
public void mouseDragged(MouseEvent evt) {
if(evtElem == null || !evtElem.isNode()) return;
int evtMod = evt.getModifiers();
Point pt = evt.getPoint();
if(dragPt != null) {
//if(dragPt.equals(pt)) return;
rubberLine(evtX,evtY,dragPt.x,dragPt.y);
dragPt = null;
}
//Added by Erol
setupArrowPoints(evt);
//Erol
processBlock: if(
evtMod == (BUTTON1_MASK|InputEvent.SHIFT_MASK)
||
evtMod == (InputEvent.BUTTON1_MASK|InputEvent.SHIFT_MASK)
)
{
if(!getGraph().isEditable()) break processBlock;
dragPt = pt;
rubberLine(evtX,evtY,dragPt.x,dragPt.y);
}
else{
//Erol
myUtil.dragNodeWithEdges(evtElem,new Point(evt.getX(),evt.getY()));
//Erol
}
// no wrap up
}
public void mouseMoved(MouseEvent evt) {
return;
}
private void highlightSelect() {
Element elem = getGraph().setCurrent(evtElem);
if(elem != null) {
elem.getDrawObject().highlightOff(DrawObject.SELECTION);
}
evtElem.getDrawObject().highlightOn(DrawObject.SELECTION);
}
private void rubberLine(int x0, int y0, int x1, int y1) {
Graphics gr = getGraphics();
gr.setXORMode(getGraph().getDrawObject().getGC().getXORColor());
gr.drawLine(x0,y0,x1,y1);
}
private void highlightDelete(Element elem, boolean turnOn) {
if(elem == null) return;
DrawObject drwobj = elem.getDrawObject();
if(drwobj == null) return;
if(turnOn) drwobj.highlightOn(DrawObject.DELETION);
else drwobj.highlightOff(DrawObject.DELETION);
if(elem.isNode()) {
Enumeration enum = ((Node)elem).edgeElements();
Edge edge = null;
while(enum.hasMoreElements()) {
edge = (Edge)enum.nextElement();
drwobj = edge.getDrawObject();
if(drwobj != null) {
if(turnOn) drwobj.highlightOn(DrawObject.DELETION);
else drwobj.highlightOff(DrawObject.DELETION);
}
}
}
}
private void doDelete(Element elem) {
if(elem == null) return;
elem.delete();
DrawPane.refreshGraph(getDrawPane().getDrawGraph());
}
//Added by Erol,Jun 19,11:44 AM
void setupArrowPoints(MouseEvent evt)
{
DrawObject curDobj,prevDobj;
int x = evt.getX();
int y = evt.getY();
Point pt = new Point(x,y);
Element startElem = evtElem;
Element curElem = getDrawPane().findContainingElement(pt);
if (startElem != null){
prevDobj = startElem.getDrawObject();
if (curElem != null)
System.out.println("I am in one object:"+curElem.toString()+
":"+pt.x+"&"+pt.y);
//startArrowPos will be first point after we left source node
if (!prevDobj.containsPaneXY(getDrawPane(),pt.x,pt.y)){
if (startArrowPos == null){
startArrowPos = pt;
System.out.println("OK I set startArrowPos:"+ pt.x+"&"+pt.y);
}
}
//endArrowPos will be last point before entered into target node
if ((curElem != null)&&(startElem != curElem)){
if (curElem != passedElem){
endArrowPos = passedPoint;
passedElem = curElem;
System.out.println("OK I set endArrowPos:"+passedPoint.x+"&"+passedPoint.y);
}
}
passedPoint = pt;
}
}
//Upto here
}
}