Coverage Report - org.argouml.uml.diagram.static_structure.ClassDiagramGraphModel
 
Classes in this File Line Coverage Branch Coverage Complexity
ClassDiagramGraphModel
0%
2/269
0%
0/230
10
 
 1  
 /* $Id: ClassDiagramGraphModel.java 18730 2010-09-11 03:00:44Z bobtarling $
 2  
  *******************************************************************************
 3  
  * Copyright (c) 2010 Contributors - see below
 4  
  * All rights reserved. This program and the accompanying materials
 5  
  * are made available under the terms of the Eclipse Public License v1.0
 6  
  * which accompanies this distribution, and is available at
 7  
  * http://www.eclipse.org/legal/epl-v10.html
 8  
  *
 9  
  * Contributors:
 10  
  *    Jason Robbins - initial implementation
 11  
  *    <see source control change log for other early contributors>
 12  
  *    
 13  
  *******************************************************************************
 14  
  */
 15  
 // Copyright (c) 1996-2007 The Regents of the University of California. All
 16  
 // Rights Reserved. Permission to use, copy, modify, and distribute this
 17  
 // software and its documentation without fee, and without a written
 18  
 // agreement is hereby granted, provided that the above copyright notice
 19  
 // and this paragraph appear in all copies.  This software program and
 20  
 // documentation are copyrighted by The Regents of the University of
 21  
 // California. The software program and documentation are supplied "AS
 22  
 // IS", without any accompanying services from The Regents. The Regents
 23  
 // does not warrant that the operation of the program will be
 24  
 // uninterrupted or error-free. The end-user understands that the program
 25  
 // was developed for research purposes and is advised not to rely
 26  
 // exclusively on the program for any reason.  IN NO EVENT SHALL THE
 27  
 // UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
 28  
 // SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS,
 29  
 // ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
 30  
 // THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
 31  
 // SUCH DAMAGE. THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY
 32  
 // WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 33  
 // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
 34  
 // PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF
 35  
 // CALIFORNIA HAS NO OBLIGATIONS TO PROVIDE MAINTENANCE, SUPPORT,
 36  
 // UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
 37  
 
 38  
 package org.argouml.uml.diagram.static_structure;
 39  
 
 40  
 import java.beans.PropertyChangeEvent;
 41  
 import java.beans.VetoableChangeListener;
 42  
 import java.util.ArrayList;
 43  
 import java.util.Collection;
 44  
 import java.util.Iterator;
 45  
 import java.util.List;
 46  
 
 47  
 import org.apache.log4j.Logger;
 48  
 import org.argouml.model.Model;
 49  
 import org.argouml.uml.CommentEdge;
 50  
 import org.argouml.uml.diagram.UMLMutableGraphSupport;
 51  
 
 52  
 /**
 53  
  * This class defines a bridge between the UML meta-model
 54  
  * representation of the design and the GraphModel interface used by
 55  
  * GEF.  This class handles only UML Class digrams.
 56  
  *
 57  
  * @author jrobbins
 58  
  */
 59  1028
 public class ClassDiagramGraphModel extends UMLMutableGraphSupport
 60  
     implements VetoableChangeListener {
 61  
     /**
 62  
      * Logger.
 63  
      */
 64  900
     private static final Logger LOG =
 65  
         Logger.getLogger(ClassDiagramGraphModel.class);
 66  
 
 67  
     ////////////////////////////////////////////////////////////////
 68  
     // GraphModel implementation
 69  
 
 70  
     /*
 71  
      * @see org.tigris.gef.graph.GraphModel#getPorts(java.lang.Object)
 72  
      */
 73  
     public List<Object> getPorts(Object nodeOrEdge) {
 74  0
         List<Object> res = new ArrayList<Object>(); 
 75  0
         if (Model.getFacade().isAClassifier(nodeOrEdge)) {
 76  0
             res.add(nodeOrEdge);
 77  
         }
 78  0
         if (Model.getFacade().isAInstance(nodeOrEdge)) {
 79  0
             res.add(nodeOrEdge);
 80  
         }
 81  0
         if (Model.getFacade().isAModel(nodeOrEdge)) {
 82  0
             res.add(nodeOrEdge);
 83  
         }
 84  0
         if (Model.getFacade().isAStereotype(nodeOrEdge)) {
 85  0
             res.add(nodeOrEdge);
 86  
         }
 87  0
         if (Model.getFacade().isASignal(nodeOrEdge)) {
 88  0
             res.add(nodeOrEdge);
 89  
         }
 90  0
         return res;
 91  
     }
 92  
 
 93  
     /*
 94  
      * @see org.tigris.gef.graph.BaseGraphModel#getOwner(java.lang.Object)
 95  
      */
 96  
     public Object getOwner(Object port) {
 97  0
         return port;
 98  
     }
 99  
 
 100  
     /**
 101  
      * Return all edges going to given port (read Model Element).
 102  
      * 
 103  
      * @param port
 104  
      *            model element to query
 105  
      * @return list of incoming connections
 106  
      */
 107  
     public List getInEdges(Object port) {
 108  
 
 109  0
         List<Object> edges = new ArrayList<Object>();
 110  
 
 111  
         // top of the hierarchy is ME:
 112  0
         if (Model.getFacade().isAModelElement(port)) {
 113  0
             Iterator it =
 114  
                 Model.getFacade().getSupplierDependencies(port).iterator();
 115  0
             while (it.hasNext()) {
 116  0
                 edges.add(it.next());
 117  
             }
 118  
         }
 119  
         // then Generalizable Element
 120  0
         if (Model.getFacade().isAGeneralizableElement(port)) {
 121  0
             Iterator it = Model.getFacade().getSpecializations(port).iterator();
 122  0
             while (it.hasNext()) {
 123  0
                 edges.add(it.next());
 124  
             }
 125  
         }
 126  
         // then Classifier & Package
 127  0
         if (Model.getFacade().isAClassifier(port)
 128  
                 || Model.getFacade().isAPackage(port)) {
 129  0
             Iterator it = Model.getFacade().getAssociationEnds(port).iterator();
 130  0
             while (it.hasNext()) {
 131  0
                 Object nextAssocEnd = it.next();
 132  
                 // navigable.... only want incoming
 133  0
                 if (Model.getFacade().isNavigable(nextAssocEnd)) {
 134  0
                     edges.add(nextAssocEnd);
 135  
                 }
 136  0
             }
 137  
         }
 138  
 
 139  0
         if (Model.getFacade().isAInstance(port)) {
 140  0
             Iterator it = Model.getFacade().getLinkEnds(port).iterator();
 141  0
             while (it.hasNext()) {
 142  0
                 edges.add(it.next());
 143  
             }
 144  
         }
 145  
 
 146  0
         return edges;
 147  
     }
 148  
 
 149  
     /*
 150  
      * @see org.tigris.gef.graph.GraphModel#getOutEdges(java.lang.Object)
 151  
      */
 152  
     public List getOutEdges(Object port) {
 153  
 
 154  0
         List<Object> edges = new ArrayList<Object>();
 155  
 
 156  
         // top of the hierarchy is ME:
 157  0
         if (Model.getFacade().isAModelElement(port)) {
 158  0
             Iterator it =
 159  
                 Model.getFacade().getClientDependencies(port).iterator();
 160  0
             while (it.hasNext()) {
 161  0
                 edges.add(it.next());
 162  
             }
 163  
         }
 164  
         // then Generalizable Element
 165  0
         if (Model.getFacade().isAGeneralizableElement(port)) {
 166  0
             Iterator it = Model.getFacade().getGeneralizations(port).iterator();
 167  0
             while (it.hasNext()) {
 168  0
                 edges.add(it.next());
 169  
             }
 170  
         }
 171  
         // then Classifier
 172  0
         if (Model.getFacade().isAClassifier(port)) {
 173  0
             Iterator it = Model.getFacade().getAssociationEnds(port).iterator();
 174  0
             while (it.hasNext()) {
 175  0
                 Object thisEnd = it.next();
 176  0
                 Object assoc = Model.getFacade().getAssociation(thisEnd);
 177  0
                 if (assoc != null) {
 178  0
                     Iterator it2 =  
 179  
                         Model.getFacade().getAssociationEnds(assoc).iterator();
 180  0
                     while (it2.hasNext()) {
 181  0
                         Object nextAssocEnd = it2.next();
 182  0
                         if (!thisEnd.equals(nextAssocEnd)
 183  
                                 && Model.getFacade().isNavigable(
 184  
                                         nextAssocEnd)) {
 185  0
                             edges.add(nextAssocEnd);
 186  
                         }
 187  0
                     }
 188  
                 }
 189  0
             }
 190  
         }
 191  
 
 192  0
         return edges;
 193  
     }
 194  
 
 195  
     ////////////////////////////////////////////////////////////////
 196  
     // MutableGraphModel implementation
 197  
 
 198  
     /*
 199  
      * @see org.tigris.gef.graph.MutableGraphModel#canAddNode(java.lang.Object)
 200  
      */
 201  
     @Override
 202  
     public boolean canAddNode(Object node) {
 203  0
         if (Model.getFacade().isAAssociation(node)
 204  
                 && !Model.getFacade().isANaryAssociation(node)) {
 205  
             // A binary association is not a node so reject.
 206  0
             LOG.debug("A binary association cannot be added as a node");
 207  0
             return false;
 208  
         }
 209  
         
 210  0
         if (super.canAddNode(node) && !containsNode(node)) {
 211  0
             return true;
 212  
         }
 213  
         
 214  0
             if (containsNode(node)) {
 215  0
             LOG.error("Addition of node of type " 
 216  
                     + node.getClass().getName()
 217  
                     + " rejected because its already in the graph model");
 218  0
                 return false;
 219  
             }
 220  0
         if (Model.getFacade().isAAssociation(node)) {
 221  
             // N.B. A node which is an Association is either a n-ary association
 222  
             // or the Class part of an AssociationClass
 223  0
             Collection ends = Model.getFacade().getConnections(node);
 224  0
             Iterator iter = ends.iterator();
 225  0
             while (iter.hasNext()) {
 226  0
                 Object classifier =
 227  
                     Model.getFacade().getClassifier(iter.next());
 228  0
                 if (!containsNode(classifier)) {
 229  0
                     LOG.error("Addition of node of type "
 230  
                             + node.getClass().getName()
 231  
                             + " rejected because it is connected to a "
 232  
                             + "classifier that is not in the diagram");
 233  0
                     return false;
 234  
                 }
 235  0
             }
 236  0
             return true;
 237  
         }
 238  
 
 239  
         // TODO: This logic may well be worth moving into the model component.
 240  
         // Provide a similar grid to the connectionsGrid
 241  0
         if (Model.getFacade().isAModel(node)) {
 242  0
             return false; // issue 3774
 243  
         }
 244  0
         if (Model.getFacade().isAClassifierRole(node)) {
 245  0
             return false;
 246  
         }
 247  0
         return Model.getFacade().isAClassifier(node)
 248  
             || Model.getFacade().isAPackage(node)
 249  
             || Model.getFacade().isAStereotype(node)
 250  
             || Model.getFacade().isASignal(node)
 251  
             || Model.getFacade().isAInstance(node);
 252  
     }
 253  
 
 254  
     /*
 255  
      * @see org.tigris.gef.graph.MutableGraphModel#canAddEdge(java.lang.Object)
 256  
      */
 257  
     @Override
 258  
     public boolean canAddEdge(Object edge) {
 259  0
         if (edge == null) {
 260  0
             return false;
 261  
         }
 262  0
         if (containsEdge(edge)) {
 263  0
             return false;
 264  
         }
 265  0
         Object sourceModelElement = null;
 266  0
         Object destModelElement = null;
 267  0
         if (Model.getFacade().isAAssociation(edge)) {
 268  0
             Collection conns = Model.getFacade().getConnections(edge);
 269  0
             if (conns.size() < 2) {
 270  0
                 LOG.error("Association rejected. Must have at least 2 ends");
 271  0
                 return false;
 272  
             }
 273  0
             Iterator iter = conns.iterator();
 274  0
             Object associationEnd0 = iter.next();
 275  0
             Object associationEnd1 = iter.next();
 276  0
             if (associationEnd0 == null || associationEnd1 == null) {
 277  0
                 LOG.error("Association rejected. An end is null");
 278  0
                 return false;
 279  
             }
 280  0
             sourceModelElement = Model.getFacade().getType(associationEnd0);
 281  0
             destModelElement = Model.getFacade().getType(associationEnd1);
 282  0
         } else if (Model.getFacade().isAAssociationEnd(edge)) {
 283  0
             sourceModelElement = Model.getFacade().getAssociation(edge);
 284  0
             destModelElement = Model.getFacade().getType(edge);
 285  0
             if (sourceModelElement == null || destModelElement == null) {
 286  0
                 LOG.error("Association end rejected. An end is null");
 287  0
                 return false;
 288  
             }
 289  
 
 290  0
             if (!containsEdge(sourceModelElement) 
 291  
                     && !containsNode(sourceModelElement)) {
 292  0
                 LOG.error("Association end rejected. The source model element ("
 293  
                         + sourceModelElement.getClass().getName()
 294  
                         + ") must be on the diagram");
 295  0
                 return false;
 296  
             }
 297  
 
 298  0
             if (!containsNode(destModelElement)) {
 299  0
                 LOG.error("Association end rejected. "
 300  
                         + "The destination model element must be "
 301  
                         + "on the diagram.");
 302  0
                 return false;
 303  
             }
 304  
 
 305  0
         } else if (Model.getFacade().isAGeneralization(edge)) {
 306  0
             sourceModelElement = Model.getFacade().getSpecific(edge);
 307  0
             destModelElement = Model.getFacade().getGeneral(edge);
 308  0
         } else if (Model.getFacade().isADependency(edge)) {
 309  0
             Collection clients = Model.getFacade().getClients(edge);
 310  0
             Collection suppliers = Model.getFacade().getSuppliers(edge);
 311  0
             if (clients == null || suppliers == null) {
 312  0
                 return false;
 313  
             }
 314  0
             sourceModelElement = clients.iterator().next();
 315  0
             destModelElement = suppliers.iterator().next();
 316  0
         } else if (Model.getFacade().isALink(edge)) {
 317  0
             Collection roles = Model.getFacade().getConnections(edge);
 318  0
             if (roles.size() < 2) {
 319  0
                 return false;
 320  
             }
 321  0
             Iterator iter = roles.iterator();
 322  0
             Object linkEnd0 = iter.next();
 323  0
             Object linkEnd1 = iter.next();
 324  0
             if (linkEnd0 == null || linkEnd1 == null) {
 325  0
                 return false;
 326  
             }
 327  0
             sourceModelElement = Model.getFacade().getInstance(linkEnd0);
 328  0
             destModelElement = Model.getFacade().getInstance(linkEnd1);
 329  0
         } else if (edge instanceof CommentEdge) {
 330  0
             sourceModelElement = ((CommentEdge) edge).getSource();
 331  0
             destModelElement = ((CommentEdge) edge).getDestination();
 332  0
         } else if (Model.getFacade().isADirectedRelationship(edge)) {
 333  0
             Collection sources = Model.getFacade().getSources(edge);
 334  0
             Collection targets = Model.getFacade().getTargets(edge);
 335  0
             if (sources.size() == 1 && targets.size() == 1) {
 336  0
                 sourceModelElement = sources.iterator().next();
 337  0
                 destModelElement = targets.iterator().next();
 338  
             } else {
 339  0
                 LOG.error("Edge rejected. More than one source or target for a DirectedRelationship");
 340  0
                 return false;
 341  
             }
 342  0
         } else {
 343  0
             return false;
 344  
         }
 345  
 
 346  0
         if (sourceModelElement == null || destModelElement == null) {
 347  0
             LOG.error("Edge rejected. Its ends are not attached to anything");
 348  0
             return false;
 349  
         }
 350  
 
 351  0
         if (!containsNode(sourceModelElement)
 352  
                 && !containsEdge(sourceModelElement)) {
 353  0
             LOG.error("Edge rejected. Its source end is attached to "
 354  
                     + sourceModelElement
 355  
                     + " but this is not in the graph model");
 356  0
             return false;
 357  
         }
 358  0
         if (!containsNode(destModelElement)
 359  
                 && !containsEdge(destModelElement)) {
 360  0
             LOG.error("Edge rejected. Its destination end is attached to "
 361  
                     + destModelElement 
 362  
                     + " but this is not in the graph model");
 363  0
             return false;
 364  
         }
 365  
 
 366  0
         return true;
 367  
     }
 368  
 
 369  
 
 370  
     /*
 371  
      * @see org.tigris.gef.graph.MutableGraphModel#addNode(java.lang.Object)
 372  
      */
 373  
     @Override
 374  
     public void addNode(Object node) {
 375  0
         if (!canAddNode(node)) {
 376  0
             return;
 377  
         }
 378  0
         getNodes().add(node);
 379  
         
 380  
         // TODO: This is probably an undesirable side effect unless the user
 381  
         // confirms it.  Placing an element on a second diagram is going to
 382  
         // potentially change its namespace. - tfm 20061208
 383  0
         if (Model.getFacade().isAModelElement(node)
 384  
                 && Model.getFacade().getNamespace(node) == null) {
 385  0
             Model.getCoreHelper().addOwnedElement(getHomeModel(), node);
 386  
         }
 387  
 
 388  0
         fireNodeAdded(node);
 389  0
     }
 390  
 
 391  
     /**
 392  
      * Add the given edge to the graph, if of the correct type.
 393  
      * Throws IllegalArgumentException if edge is null or either of its
 394  
      * ends are null.
 395  
      *
 396  
      * @param edge the edge to be added
 397  
      */
 398  
     @Override
 399  
     public void addEdge(Object edge) {
 400  0
         if (edge == null) {
 401  0
             throw new IllegalArgumentException("Cannot add a null edge");
 402  
         }
 403  
 
 404  0
         if (getDestPort(edge) == null || getSourcePort(edge) == null) {
 405  0
             throw new IllegalArgumentException(
 406  
                     "The source and dest port should be provided on an edge");
 407  
         }
 408  
 
 409  0
         if (LOG.isInfoEnabled()) {
 410  0
             LOG.info("Adding an edge of type "
 411  
                    + edge.getClass().getName()
 412  
                    + " to class diagram.");
 413  
         }
 414  
 
 415  0
         if (!canAddEdge(edge)) {
 416  0
             LOG.info("Attempt to add edge rejected");
 417  0
             return;
 418  
         }
 419  
 
 420  0
         getEdges().add(edge);
 421  
  
 422  
         // TODO: assumes public
 423  
         // TODO: This is probably an undesirable side effect unless the user
 424  
         // confirms it.  Placing an element on a second diagram is going to
 425  
         // potentially change its namespace. - tfm 20061208
 426  0
         if (Model.getFacade().isAModelElement(edge)
 427  
                 && Model.getFacade().getNamespace(edge) == null
 428  
                 && !Model.getFacade().isAAssociationEnd(edge)) {
 429  0
                 Model.getCoreHelper().addOwnedElement(getHomeModel(), edge);
 430  
         }
 431  0
         fireEdgeAdded(edge);
 432  0
     }
 433  
 
 434  
 
 435  
     /**
 436  
      * Add the edges from the given node. For example, this method lets you add
 437  
      * an existing association between two figclassifiers.
 438  
      * 
 439  
      * @param node
 440  
      *            the model element to query for connections
 441  
      */
 442  
     @Override
 443  
     public void addNodeRelatedEdges(Object node) {
 444  0
         super.addNodeRelatedEdges(node);
 445  
 
 446  0
         if (Model.getFacade().isAClassifier(node)) {
 447  0
             Collection ends = Model.getFacade().getAssociationEnds(node);
 448  0
             Iterator iter = ends.iterator();
 449  0
             while (iter.hasNext()) {
 450  0
                 final Object associationEnd = iter.next();
 451  0
                 Object association =
 452  
                         Model.getFacade().getAssociation(associationEnd);
 453  0
                 if (Model.getFacade().isANaryAssociation(association) 
 454  
                         && canAddEdge(associationEnd)) {
 455  0
                     addEdge(associationEnd);
 456  0
                 } else if (canAddEdge(association)){
 457  0
                     addEdge(association);
 458  
                 }
 459  0
             }
 460  
         }
 461  0
         if (Model.getFacade().isAGeneralizableElement(node)) {
 462  0
             Collection generalizations =
 463  
                 Model.getFacade().getGeneralizations(node);
 464  0
             Iterator iter = generalizations.iterator();
 465  0
             while (iter.hasNext()) {
 466  0
                 Object generalization = iter.next();
 467  0
                 if (canAddEdge(generalization)) {
 468  0
                     addEdge(generalization);
 469  
                     // return;
 470  
                 }
 471  0
             }
 472  0
             Collection specializations =
 473  
                 Model.getFacade().getSpecializations(node);
 474  0
             iter = specializations.iterator();
 475  0
             while (iter.hasNext()) {
 476  0
                 Object specialization = iter.next();
 477  0
                 if (canAddEdge(specialization)) {
 478  0
                     addEdge(specialization);
 479  
                     // return;
 480  
                 }
 481  0
             }
 482  
         }
 483  0
         if (Model.getFacade().isAAssociation(node)) {
 484  0
             Collection ends = Model.getFacade().getConnections(node);
 485  0
             Iterator iter = ends.iterator();
 486  0
             while (iter.hasNext()) {
 487  0
                 Object associationEnd = iter.next();
 488  0
                 if (canAddEdge(associationEnd)) {
 489  0
                     addEdge(associationEnd);
 490  
                 }
 491  0
             }
 492  
         }
 493  0
     }
 494  
 
 495  
     ////////////////////////////////////////////////////////////////
 496  
     // VetoableChangeListener implementation
 497  
 
 498  
     /*
 499  
      * @see java.beans.VetoableChangeListener#vetoableChange(java.beans.PropertyChangeEvent)
 500  
      */
 501  
     public void vetoableChange(PropertyChangeEvent pce) {
 502  
         //throws PropertyVetoException
 503  
 
 504  0
         if ("ownedElement".equals(pce.getPropertyName())) {
 505  0
             List oldOwned = (List) pce.getOldValue();
 506  0
             Object elementImport = pce.getNewValue();
 507  0
             Object modelElement =
 508  
                     Model.getFacade().getModelElement(elementImport);
 509  
             //MModelElement modelElement = elementImport.getModelElement();
 510  0
             if (oldOwned.contains(elementImport)) {
 511  0
                 LOG.debug("model removed " + modelElement);
 512  0
                 if (Model.getFacade().isAClassifier(modelElement)) {
 513  0
                     removeNode(modelElement);
 514  
                 }
 515  0
                 if (Model.getFacade().isAPackage(modelElement)) {
 516  0
                     removeNode(modelElement);
 517  
                 }
 518  0
                 if (Model.getFacade().isAAssociation(modelElement)) {
 519  0
                     removeEdge(modelElement);
 520  
                 }
 521  0
                 if (Model.getFacade().isADependency(modelElement)) {
 522  0
                     removeEdge(modelElement);
 523  
                 }
 524  0
                 if (Model.getFacade().isAGeneralization(modelElement)) {
 525  0
                     removeEdge(modelElement);
 526  
                 }
 527  
             } else {
 528  0
                 LOG.debug("model added " + modelElement);
 529  
             }
 530  
         }
 531  0
     }
 532  
 
 533  
 
 534  
     /**
 535  
      * The UID.
 536  
      */
 537  
     static final long serialVersionUID = -2638688086415040146L;
 538  
 
 539  
 
 540  
     /**
 541  
      * When rerouting an edge, this is the first method to
 542  
      * be called by SelectionRerouteEdge, in order to determine
 543  
      * whether the graphmodel will allow the change.<p>
 544  
      *
 545  
      * Restricted to class-association changes for now.
 546  
      *
 547  
      * @param newNode this is the new node that one of the ends is dragged to.
 548  
      * @param oldNode this is the existing node that is already connected.
 549  
      * @param edge this is the edge that is being dragged/rerouted
 550  
      *
 551  
      * @return whether or not the rerouting is allowed
 552  
      */
 553  
     @Override
 554  
     public boolean canChangeConnectedNode(Object newNode, Object oldNode,
 555  
                                           Object edge) {
 556  
 
 557  
         // prevent no changes...
 558  0
         if (newNode == oldNode) {
 559  0
             return false;
 560  
         }
 561  
 
 562  
         // check parameter types:
 563  0
         if (!(Model.getFacade().isAClass(newNode)
 564  
                 || Model.getFacade().isAClass(oldNode)
 565  
                 || Model.getFacade().isAAssociation(edge))) {
 566  0
             return false;
 567  
         }
 568  
 
 569  0
         return true;
 570  
     }
 571  
 
 572  
     /**
 573  
      * Reroutes the connection to the old node to be connected to
 574  
      * the new node.
 575  
      *
 576  
      * delegates to rerouteXXX(,,,) for each of the 4 possible edges in
 577  
      * a class diagram: Association, Dependency, Generalization, Link.
 578  
      * TODO: This should probably be in superclass. Many Figs can be on
 579  
      * several diagram types.
 580  
      *
 581  
      * @param newNode this is the new node that one of the ends is dragged to.
 582  
      * @param oldNode this is the existing node that is already connected.
 583  
      * @param edge this is the edge that is being dragged/rerouted
 584  
      * @param isSource tells us which end is being rerouted.
 585  
      */
 586  
     @Override
 587  
     public void changeConnectedNode(Object newNode, Object oldNode,
 588  
                                     Object edge, boolean isSource) {
 589  0
         if (Model.getFacade().isAAssociation(edge)) {
 590  0
             rerouteAssociation(newNode,  oldNode,  edge,  isSource);
 591  0
         } else if (Model.getFacade().isAGeneralization(edge)) {
 592  0
             rerouteGeneralization(newNode,  oldNode,  edge,  isSource);
 593  0
         } else if (Model.getFacade().isADependency(edge)) {
 594  0
             rerouteDependency(newNode,  oldNode,  edge,  isSource);
 595  0
         } else if (Model.getFacade().isALink(edge)) {
 596  0
             rerouteLink(newNode,  oldNode,  edge,  isSource);
 597  
         }
 598  0
     }
 599  
 
 600  
     /**
 601  
      * Helper method for changeConnectedNode.
 602  
      * TODO: This should probably be in superclass. Associations can be on
 603  
      * several diagram types.
 604  
      */
 605  
     private void rerouteAssociation(Object newNode, Object oldNode,
 606  
                                     Object edge, boolean isSource) {
 607  
         // check param types: only some connections are legal uml connections:
 608  
 
 609  0
         if (!(Model.getFacade().isAClassifier(newNode))
 610  
             || !(Model.getFacade().isAClassifier(oldNode))) {
 611  0
             return;
 612  
         }
 613  
 
 614  
         // can't have a connection between 2 interfaces:
 615  
         // get the 'other' end type
 616  0
         Object otherNode = null;
 617  
 
 618  0
         if (isSource) {
 619  0
             otherNode = Model.getCoreHelper().getDestination(edge);
 620  
         } else {
 621  0
             otherNode = Model.getCoreHelper().getSource(edge);
 622  
         }
 623  
 
 624  0
         if (Model.getFacade().isAInterface(newNode)
 625  
                 && Model.getFacade().isAInterface(otherNode)) {
 626  0
             return;
 627  
         }
 628  
 
 629  
         // cast the params
 630  0
         Object edgeAssoc = edge;
 631  
 
 632  0
         Object theEnd = null;
 633  0
         Object theOtherEnd = null;
 634  0
         Collection connections = Model.getFacade().getConnections(edgeAssoc);
 635  0
         Iterator iter = connections.iterator();
 636  0
         if (isSource) {
 637  
             // rerouting the source:
 638  0
             theEnd = iter.next();
 639  0
             theOtherEnd = iter.next();
 640  
         } else {
 641  
             // rerouting the destination:
 642  0
             theOtherEnd = iter.next();
 643  0
             theEnd = iter.next();
 644  
         }
 645  
 
 646  
         //set the new end type!
 647  0
         Model.getCoreHelper().setType(theEnd, newNode);
 648  0
     }
 649  
 
 650  
     /**
 651  
      * helper method for changeConnectedNode.<p>
 652  
      *
 653  
      * empty at the moment
 654  
      */
 655  
     private void rerouteGeneralization(Object newNode, Object oldNode,
 656  
                                        Object edge, boolean isSource) {
 657  
         // empty at the moment
 658  0
     }
 659  
 
 660  
     /**
 661  
      * Helper method for changeConnectedNode.<p>
 662  
      *
 663  
      * empty at the moment
 664  
      */
 665  
     private void rerouteDependency(Object newNode, Object oldNode,
 666  
                                    Object edge, boolean isSource) {
 667  
         // empty at the moment
 668  0
     }
 669  
 
 670  
     /**
 671  
      * helper method for changeConnectedNode.<p>
 672  
      *
 673  
      * Empty at the moment
 674  
      */
 675  
     private void rerouteLink(Object newNode, Object oldNode,
 676  
                              Object edge, boolean isSource) {
 677  
         // empty at the moment
 678  
 
 679  0
     }
 680  
 }