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 } }