001    /*
002      Copyright (C) 2002 Renaud Pawlak
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      USA. */
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.Connector;
024    import CH.ifa.draw.framework.Drawing;
025    import CH.ifa.draw.framework.Figure;
026    import CH.ifa.draw.framework.FigureEnumeration;
027    import CH.ifa.draw.standard.AbstractTool;
028    import CH.ifa.draw.util.Geom;
029    import org.objectweb.jac.core.Wrapping;
030    import org.objectweb.jac.core.Wrappee;
031    import org.objectweb.jac.ide.ModelElement;
032    import org.objectweb.jac.ide.PointcutLink;
033    import org.objectweb.jac.ide.Diagram;
034    import org.objectweb.jac.util.Log;
035    import java.awt.Point;
036    import java.awt.event.MouseEvent;
037    import java.util.Enumeration;
038    
039    public  class PointcutLinkCreationTool extends AbstractTool {
040    
041       /**
042        * the anchor point of the interaction
043        */
044       private Connector   myStartConnector;
045       private Connector   myEndConnector;
046       private Connector   myTargetConnector;
047    
048       private Figure myTarget;
049    
050       /**
051        * the currently created figure
052        */
053       private ConnectionFigure  myConnection;
054    
055       /**
056        * the figure that was actually added
057        * Note, this can be a different figure from the one which has been created.
058        */
059       private Figure myAddedFigure;
060    
061       /**
062        * the prototypical figure that is used to create new
063        * connections.
064        */
065       private ConnectionFigure  fPrototype;
066    
067    
068       public PointcutLinkCreationTool(DrawingEditor newDrawingEditor, ConnectionFigure newPrototype) {
069          super(newDrawingEditor);
070          fPrototype = newPrototype;
071       }
072    
073       /**
074        * Handles mouse move events in the drawing view.
075        */
076       public void mouseMove(MouseEvent e, int x, int y) {
077          trackConnectors(e, x, y);
078       }
079    
080       /**
081        * Manipulates connections in a context dependent way. If the
082        * mouse down hits a figure start a new connection. If the mousedown
083        * hits a connection split a segment or join two segments.
084        */
085       public void mouseDown(MouseEvent e, int x, int y)
086       {
087          int ex = e.getX();
088          int ey = e.getY();
089          setTargetFigure(findConnectionStart(ex, ey, drawing()));
090          if (getTargetFigure() != null
091              && getTargetFigure().getClass()==AspectFigure.class) {
092             setStartConnector(findConnector(ex, ey, getTargetFigure()));
093             if (getStartConnector() != null) {
094                Point p = new Point(ex, ey);
095                setConnection(createConnection());
096                getConnection().startPoint(p.x, p.y);
097                getConnection().endPoint(p.x, p.y);
098                setAddedFigure(view().add(getConnection()));
099             }
100          }
101       }
102    
103       /**
104        * Adjust the created connection or split segment.
105        */
106       public void mouseDrag(MouseEvent e, int x, int y) {
107          Point p = new Point(e.getX(), e.getY());
108          if (getConnection() != null) {
109             trackConnectors(e, x, y);
110             if (getTargetConnector() != null) {
111                p = Geom.center(getTargetConnector().displayBox());
112             }
113             getConnection().endPoint(p.x, p.y);
114          }
115       }
116    
117       /**
118        * Connects the figures if the mouse is released over another
119        * figure.
120        */
121       public void mouseUp(MouseEvent e, int x, int y) {
122          Figure c = null;
123          if (getStartConnector() != null) {
124             c = findTarget(e.getX(), e.getY(), drawing());
125          }
126          
127          if (c != null && (c.getClass()==ClassFigure.class ||
128                            c.getClass()==InstanceFigure.class)) {
129             setEndConnector(findConnector(e.getX(), e.getY(), c));
130             if (getEndConnector() != null) {
131                getConnection().connectStart(getStartConnector());
132                getConnection().connectEnd(getEndConnector());
133                getConnection().updateConnection();
134                
135                /*
136                setUndoActivity(createUndoActivity());
137                getUndoActivity().setAffectedFigures(
138                   new SingleFigureEnumerator(getAddedFigure()));
139                */
140                AspectFigure source = (AspectFigure)getStartConnector().owner();
141                ModelElementFigure target = (ModelElementFigure)c;
142                Log.trace("figures","creating a new poincut link between "+
143                          source.getSubstance()+" and "+target.getSubstance());
144                
145                createRelation(source.getClassElement(),target.getSubstance());
146                
147             }
148          }
149          else if (getConnection() != null) {
150             ((DiagramView)editor()).showStatus("Invalid or empty ending element for relation.");
151             view().remove(getConnection());
152          }
153          
154          setConnection(null);
155          setStartConnector(null);
156          setEndConnector(null);
157          setAddedFigure(null);
158          editor().toolDone();
159       }
160    
161    
162       protected void createRelation(org.objectweb.jac.ide.Class source, ModelElement target) {
163    
164          if(source != null && target != null ) {
165             PointcutLink rel = new PointcutLink();
166             rel.setStart(source);
167             rel.setEnd(target);
168             // ***         ((LinkFigure)getConnection()).setSubstance(rel);
169             LinkFigure linkFigure=(LinkFigure)getConnection();
170             org.objectweb.jac.ide.LinkFigure linkFig = 
171                new org.objectweb.jac.ide.LinkFigure(rel);
172             linkFigure.setLinkFigure(linkFig);
173    
174             view().add(linkFigure.createName("newPointcut"));
175             view().add(linkFigure.createEndRole("ALL:ALL"));
176             view().add(linkFigure.createStartRole("?"));
177             //view().add(((LinkFigure)getConnection()).createStartCardinality("0-1"));
178             //view().add(((LinkFigure)getConnection()).createEndCardinality("0-1"));
179             ((org.objectweb.jac.ide.Aspect)source).addPointcutLink(rel);
180    
181             Diagram diagram = (Diagram)((DiagramView)editor()).getSubstance();
182    
183             diagram.addFigure(linkFig);
184    
185             Wrapping.invokeRoleMethod((Wrappee)rel,"registerObject",
186                                       new Object[]{getConnection(),null});
187          }
188       }
189    
190       public void deactivate() {
191          super.deactivate();
192          if (getTargetFigure() != null) {
193             getTargetFigure().connectorVisibility(false);
194          }
195       }
196    
197       /**
198        * Creates the ConnectionFigure. By default the figure prototype is
199        * cloned.
200        */
201       protected ConnectionFigure createConnection() {
202          return (ConnectionFigure)fPrototype.clone();
203       }
204       
205       /**
206        * Finds a connectable figure target.
207        */
208       protected Figure findSource(int x, int y, Drawing drawing) {
209          return findConnectableFigure(x, y, drawing);
210       }
211       
212       /**
213        * Finds a connectable figure target.
214        */
215       protected Figure findTarget(int x, int y, Drawing drawing) {
216          Figure target = findConnectableFigure(x, y, drawing);
217          Figure start = getStartConnector().owner();
218          
219          if (target != null
220              && getConnection() != null
221              && target.canConnect()
222              && !target.includes(start)
223              && getConnection().canConnect(start, target)) {
224             return target;
225          }
226          return null;
227       }
228       
229       /**
230        * Finds an existing connection figure.
231        */
232       protected ConnectionFigure findConnection(int x, int y, Drawing drawing) {
233          Enumeration k = drawing.figuresReverse();
234          while (k.hasMoreElements()) {
235             Figure figure = (Figure) k.nextElement();
236             figure = figure.findFigureInside(x, y);
237             if (figure != null && (figure instanceof ConnectionFigure)) {
238                return (ConnectionFigure)figure;
239             }
240          }
241          return null;
242       }
243       
244       private void setConnection(ConnectionFigure newConnection) {
245          myConnection = newConnection;
246       }
247       
248       /**
249        * Gets the connection which is created by this tool
250        */
251       protected ConnectionFigure getConnection() {
252          return myConnection;
253       }
254       
255       protected void trackConnectors(MouseEvent e, int x, int y) {
256          Figure c = null;
257          
258          if (getStartConnector() == null) {
259             c = findSource(x, y, drawing());
260          }
261          else {
262             c = findTarget(x, y, drawing());
263          }
264          
265          // track the figure containing the mouse
266          if (c != getTargetFigure()) {
267             if (getTargetFigure() != null) {
268                getTargetFigure().connectorVisibility(false);
269             }
270             setTargetFigure(c);
271             if (getTargetFigure() != null) {
272                getTargetFigure().connectorVisibility(true);
273             }
274          }
275          
276          Connector cc = null;
277          if (c != null) {
278             cc = findConnector(e.getX(), e.getY(), c);
279          }
280          if (cc != getTargetConnector()) {
281             setTargetConnector(cc);
282          }
283          
284          view().checkDamage();
285       }
286       
287       private Connector findConnector(int x, int y, Figure f) {
288          return f.connectorAt(x, y);
289       }
290       
291       /**
292        * Finds a connection start figure.
293        */
294       protected Figure findConnectionStart(int x, int y, Drawing drawing) {
295          Figure target = findConnectableFigure(x, y, drawing);
296          if ((target != null) && target.canConnect()) {
297             return target;
298          }
299          return null;
300       }
301       
302       private Figure findConnectableFigure(int x, int y, Drawing drawing) {
303          FigureEnumeration k = drawing.figuresReverse();
304          while (k.hasMoreElements()) {
305             Figure figure = k.nextFigure();
306             if (!figure.includes(getConnection()) && figure.canConnect()
307                 && figure.containsPoint(x, y)) {
308                return figure;
309             }
310          }
311          return null;
312       }
313       
314       private void setStartConnector(Connector newStartConnector) {
315          myStartConnector = newStartConnector;
316       }
317       
318       protected Connector getStartConnector() {
319          return myStartConnector;
320       }
321       
322       private void setEndConnector(Connector newEndConnector) {
323          myEndConnector = newEndConnector;
324       }
325       
326       protected Connector getEndConnector() {
327          return myEndConnector;
328       }
329    
330       private void setTargetConnector(Connector newTargetConnector) {
331          myTargetConnector = newTargetConnector;
332       }
333            
334       protected Connector getTargetConnector() {
335          return myTargetConnector;
336       }
337            
338       private void setTargetFigure(Figure newTarget) {
339          myTarget = newTarget;
340       }
341            
342       protected Figure getTargetFigure() {
343          return myTarget;
344       }
345    
346       /**
347        * Gets the figure that was actually added
348        * Note, this can be a different figure from the one which has been created.
349        */
350       protected Figure getAddedFigure() {
351          return myAddedFigure;
352       }
353    
354       private void setAddedFigure(Figure newAddedFigure) {
355          myAddedFigure = newAddedFigure;
356       }
357    
358       /**
359        * Factory method for undo activity
360        */
361       /*
362       protected Undoable createUndoActivity() {
363          return new ConnectionTool.UndoActivity(view(), getConnection());
364       }
365    
366       public static class UndoActivity extends UndoableAdapter {
367    
368          private ConnectionFigure  myConnection;
369          private Connector   myStartConnector;
370          private Connector   myEndConnector;
371    
372          public UndoActivity(DrawingView newDrawingView, ConnectionFigure newConnection) {
373             super(newDrawingView);
374             setConnection(newConnection);
375             myStartConnector = getConnection().getStartConnector();
376             myEndConnector = getConnection().getEndConnector();
377             setUndoable(true);
378             setRedoable(true);
379          }
380          public boolean undo() {
381             if (!super.undo()) {
382                return false;
383             }
384    
385             getConnection().disconnectStart();
386             getConnection().disconnectEnd();
387                            
388             FigureEnumeration fe = getAffectedFigures();
389             while (fe.hasMoreElements()) {
390                getDrawingView().drawing().orphan(fe.nextFigure());
391             }
392    
393             getDrawingView().clearSelection();
394    
395             return true;
396          }
397    
398          public boolean redo() {
399             if (!super.redo()) {
400                return false;
401             }
402    
403             getConnection().connectStart(myStartConnector);
404             getConnection().connectEnd(myEndConnector);
405             getConnection().updateConnection();
406    
407             getDrawingView().insertFigures(getAffectedFigures(), 0, 0, false);
408    
409             return true;
410          }
411    
412          private void setConnection(ConnectionFigure newConnection) {
413             myConnection = newConnection;
414          }
415                    
416          /**
417           * Gets the currently created figure
418           * /
419          protected ConnectionFigure getConnection() {
420             return myConnection;
421          }
422       }
423    */
424    }