001    /*
002      Copyright (C) 2002-2003 Renaud Pawlak <renaud@aopsys.com>
003    
004      This program is free software; you can redistribute it and/or modify
005      it under the terms of the GNU Lesser General Public License as
006      published by the Free Software Foundation; either version 2 of the
007      License, or (at your option) any later version.
008    
009      This program is distributed in the hope that it will be useful,
010      but WITHOUT ANY WARRANTY; without even the implied warranty of
011      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
012      GNU Lesser General Public License for more details.
013    
014      You should have received a copy of the GNU Lesser General Public
015      License along with this program; if not, write to the Free Software
016      Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
017    */
018    
019    package org.objectweb.jac.ide.diagrams;
020    
021    import CH.ifa.draw.framework.DrawingEditor;
022    import CH.ifa.draw.framework.ConnectionFigure;
023    import CH.ifa.draw.framework.Figure;
024    import CH.ifa.draw.framework.FigureEnumeration;
025    import CH.ifa.draw.framework.Connector;
026    import CH.ifa.draw.framework.Drawing;
027    
028    import CH.ifa.draw.util.Geom;
029    
030    import org.objectweb.jac.ide.Class;
031    import org.objectweb.jac.util.Log;
032    
033    import java.awt.Point;
034    import java.awt.event.MouseEvent;
035    import java.util.Enumeration;
036    
037    public  class RelationLinkCreationTool extends AbstractTool {
038    
039       /** the anchor point of the interaction */
040       Connector   myStartConnector;
041       Connector   myEndConnector;
042       Connector   myTargetConnector;
043    
044       Figure myTarget;
045    
046       /** the currently created figure */
047       LinkFigure  myConnection;
048    
049       public RelationLinkCreationTool(DrawingEditor newDrawingEditor) {
050          super(newDrawingEditor);
051       }
052    
053       /**
054        * Handles mouse move events in the drawing view.
055        */
056       public void mouseMove(MouseEvent e, int x, int y) {
057          trackConnectors(e, x, y);
058       }
059    
060       /**
061        * Manipulates connections in a context dependent way. If the
062        * mouse down hits a figure start a new connection. If the mousedown
063        * hits a connection split a segment or join two segments.
064        */
065       public void mouseDown(MouseEvent e, int x, int y)
066       {
067          Log.trace("diagram","mouseDown");
068          int ex = e.getX();
069          int ey = e.getY();
070          myTarget = findConnectionStart(ex, ey, drawing());
071          Log.trace("diagram","target figure = "+myTarget);
072          if (myTarget != null
073              && (myTarget.getClass()==ClassFigure.class ||
074                  myTarget.getClass()==AspectFigure.class)) {
075             myStartConnector = findConnector(ex, ey, myTarget);
076             if (myStartConnector != null) {
077                Point p = new Point(ex, ey);
078                myConnection = createLinkFigure();
079                myConnection.startPoint(p.x, p.y);
080                myConnection.endPoint(p.x, p.y);
081                view().add(myConnection);
082             }
083          }
084       }
085    
086       protected LinkFigure createLinkFigure() {
087          return new RelationLinkFigure();
088       }
089    
090       /**
091        * Adjust the created connection or split segment.
092        */
093       public void mouseDrag(MouseEvent e, int x, int y) {
094          Log.trace("diagram",2,"mouseDrag "+x+","+y);
095          Point p = new Point(e.getX(), e.getY());
096          if (myConnection != null) {
097             trackConnectors(e, x, y);
098             if (myTargetConnector != null) {
099                p = Geom.center(myTargetConnector.displayBox());
100             }
101             myConnection.endPoint(p.x, p.y);
102          }
103       }
104    
105       /**
106        * Connects the figures if the mouse is released over another
107        * figure.
108        */
109       public void mouseUp(MouseEvent e, int x, int y) {
110          Log.trace("diagram","mouseUp "+x+","+y);
111          Log.trace("diagram","  myStartConnector="+myStartConnector);
112          ModelElementFigure dest = null;
113          if (myStartConnector != null) {
114             dest = findTarget(e.getX(), e.getY(), drawing());
115             Log.trace("diagram","  dest="+dest);
116          }
117          
118          if (dest instanceof ClassFigure) {
119             myEndConnector = findConnector(e.getX(), e.getY(), dest);
120             Log.trace("diagram","  myEndConnector="+myEndConnector);
121             if (myEndConnector != null) {
122                myConnection.connectStart(myStartConnector);
123                myConnection.connectEnd(myEndConnector);
124                myConnection.updateConnection();
125                ClassFigure source = (ClassFigure)myStartConnector.owner();
126                createRelation(source.getClassElement(),
127                               ((ClassFigure)dest).getClassElement());
128             }
129          }
130          else if (myConnection != null) {
131             ((DiagramView)editor()).showStatus(
132                "Invalid or empty ending element for relation.");
133             view().remove(myConnection);
134          }
135          
136          myConnection = null;
137          myStartConnector = null;
138          myEndConnector = null;
139          editor().toolDone();
140       }
141    
142       /**
143        * Create a RelationLink between two classes.
144        * @param source start class of the link
145        * @param target end class of the link
146        */
147       protected void createRelation(Class source, Class target) {
148          if (source != null && target != null) {
149             diagramView().createRelation(source,target,(RelationLinkFigure)myConnection,false);
150             view().clearSelection();
151             view().addToSelection(myConnection);
152          }
153       }
154    
155       public void deactivate() {
156          super.deactivate();
157          if (myTarget != null) {
158             myTarget.connectorVisibility(false);
159          }
160       }
161    
162    
163       /**
164        * Finds a connectable figure target.
165        */
166       protected Figure findSource(int x, int y, Drawing drawing) {
167          return findConnectableFigure(x, y, drawing);
168       }
169    
170       /**
171        * Finds a connectable figure target.
172        */
173       protected ModelElementFigure findTarget(int x, int y, Drawing drawing) {
174          ModelElementFigure target = findConnectableFigure(x, y, drawing);
175          Figure start = myStartConnector.owner();
176    
177          if (target != null
178              && myConnection != null
179              && target.canConnect()
180              && myConnection.canConnect(start, target)) {
181             return target;
182          }
183          return null;
184       }
185    
186       /**
187        * Finds an existing connection figure.
188        */
189       protected ConnectionFigure findConnection(int x, int y, Drawing drawing) {
190          Enumeration k = drawing.figuresReverse();
191          while (k.hasMoreElements()) {
192             Figure figure = (Figure) k.nextElement();
193             figure = figure.findFigureInside(x, y);
194             if (figure != null && (figure instanceof ConnectionFigure)) {
195                return (ConnectionFigure)figure;
196             }
197          }
198          return null;
199       }
200    
201       protected void trackConnectors(MouseEvent e, int x, int y) {
202          Figure c = null;
203    
204          if (myStartConnector == null) {
205             c = findSource(x, y, drawing());
206          }
207          else {
208             c = findTarget(x, y, drawing());
209          }
210    
211          // track the figure containing the mouse
212          if (c != myTarget) {
213             if (myTarget != null) {
214                myTarget.connectorVisibility(false);
215             }
216             myTarget = c;
217             if (myTarget != null) {
218                myTarget.connectorVisibility(true);
219             }
220          }
221    
222          Connector cc = null;
223          if (c != null) {
224             cc = findConnector(e.getX(), e.getY(), c);
225          }
226          if (cc != myTargetConnector) {
227             myTargetConnector = cc;
228          }
229    
230          view().checkDamage();
231       }
232    
233       private Connector findConnector(int x, int y, Figure f) {
234          return f.connectorAt(x, y);
235       }
236    
237       /**
238        * Finds a connection start figure.
239        */
240       protected Figure findConnectionStart(int x, int y, Drawing drawing) {
241          Figure target = findConnectableFigure(x, y, drawing);
242          if ((target != null) && target.canConnect()) {
243             return target;
244          }
245          return null;
246       }
247    
248       private ModelElementFigure findConnectableFigure(
249          int x, int y, Drawing drawing)
250       {   
251          FigureEnumeration k = drawing.figuresReverse();
252          while (k.hasMoreElements()) {
253             Figure figure = k.nextFigure();
254             if (!figure.includes(myConnection) && figure.canConnect()
255                 && figure.containsPoint(x, y)) {
256                return (ModelElementFigure)figure;
257             }
258          }
259          return null;
260       }
261    
262    }