Coverage Report - org.argouml.uml.diagram.state.StateDiagramGraphModel
 
Classes in this File Line Coverage Branch Coverage Complexity
StateDiagramGraphModel
5%
9/165
2%
3/128
6.765
 
 1  
 /* $Id: StateDiagramGraphModel.java 18967 2011-01-11 23:02:22Z bobtarling $
 2  
  *****************************************************************************
 3  
  * Copyright (c) 2009 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  
  *    bobtarling
 11  
  *****************************************************************************
 12  
  *
 13  
  * Some portions of this file was previously release using the BSD License:
 14  
  */
 15  
 
 16  
 // Copyright (c) 1996-2006 The Regents of the University of California. All
 17  
 // Rights Reserved. Permission to use, copy, modify, and distribute this
 18  
 // software and its documentation without fee, and without a written
 19  
 // agreement is hereby granted, provided that the above copyright notice
 20  
 // and this paragraph appear in all copies. This software program and
 21  
 // documentation are copyrighted by The Regents of the University of
 22  
 // California. The software program and documentation are supplied "AS
 23  
 // IS", without any accompanying services from The Regents. The Regents
 24  
 // does not warrant that the operation of the program will be
 25  
 // uninterrupted or error-free. The end-user understands that the program
 26  
 // was developed for research purposes and is advised not to rely
 27  
 // exclusively on the program for any reason. IN NO EVENT SHALL THE
 28  
 // UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
 29  
 // SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS,
 30  
 // ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
 31  
 // THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
 32  
 // SUCH DAMAGE. THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY
 33  
 // WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 34  
 // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
 35  
 // PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF
 36  
 // CALIFORNIA HAS NO OBLIGATIONS TO PROVIDE MAINTENANCE, SUPPORT,
 37  
 // UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
 38  
 
 39  
 package org.argouml.uml.diagram.state;
 40  
 
 41  
 import java.beans.PropertyChangeEvent;
 42  
 import java.beans.VetoableChangeListener;
 43  
 import java.util.ArrayList;
 44  
 import java.util.Collection;
 45  
 import java.util.Collections;
 46  
 import java.util.Iterator;
 47  
 import java.util.List;
 48  
 
 49  
 import org.apache.log4j.Logger;
 50  
 import org.argouml.kernel.ProjectManager;
 51  
 import org.argouml.model.Model;
 52  
 import org.argouml.uml.CommentEdge;
 53  
 import org.argouml.uml.diagram.UMLMutableGraphSupport;
 54  
 import org.tigris.gef.presentation.Fig;
 55  
 
 56  
 /**
 57  
  * This class defines a bridge between the UML meta-model representation of the
 58  
  * design and the GraphModel interface used by GEF. This class handles UML
 59  
  * Statemachine Diagrams, and is also used for Activity diagrams.
 60  
  */
 61  58
 public class StateDiagramGraphModel extends UMLMutableGraphSupport implements
 62  
         VetoableChangeListener {
 63  
 
 64  
     /**
 65  
      * Logger.
 66  
      */
 67  56
     private static final Logger LOG =
 68  
         Logger.getLogger(StateDiagramGraphModel.class);
 69  
 
 70  
 
 71  
     /**
 72  
      * The statemachine we are diagramming.
 73  
      */
 74  
     private Object machine;
 75  
 
 76  
     ////////////////////////////////////////////////////////////////
 77  
     // accessors
 78  
 
 79  
     /**
 80  
      * @return the statemachine of this diagram
 81  
      */
 82  
     public Object getMachine() {
 83  508
         return machine;
 84  
     }
 85  
 
 86  
     /**
 87  
      * @param sm   the statemachine of this diagram
 88  
      */
 89  
     public void setMachine(Object sm) {
 90  
 
 91  58
         if (!Model.getFacade().isAStateMachine(sm)) {
 92  0
             throw new IllegalArgumentException();
 93  
         }
 94  
 
 95  58
         if (sm != null) {
 96  58
             machine = sm;
 97  
         }
 98  58
     }
 99  
 
 100  
     ////////////////////////////////////////////////////////////////
 101  
     // GraphModel implementation
 102  
 
 103  
     
 104  
     /*
 105  
      * @see org.tigris.gef.graph.GraphModel#getPorts(java.lang.Object)
 106  
      */
 107  
     public List getPorts(Object nodeOrEdge) {
 108  0
         List res = new ArrayList();
 109  0
         if (Model.getFacade().isAState(nodeOrEdge)) {
 110  0
             res.add(nodeOrEdge);
 111  
         }
 112  0
         if (Model.getFacade().isAPseudostate(nodeOrEdge)) {
 113  0
             res.add(nodeOrEdge);
 114  
         }
 115  0
         return res;
 116  
     }
 117  
 
 118  
     /*
 119  
      * @see org.tigris.gef.graph.BaseGraphModel#getOwner(java.lang.Object)
 120  
      */
 121  
     public Object getOwner(Object port) {
 122  0
         return port;
 123  
     }
 124  
 
 125  
     /*
 126  
      * @see org.tigris.gef.graph.GraphModel#getInEdges(java.lang.Object)
 127  
      */
 128  
     public List getInEdges(Object port) {
 129  0
         if (Model.getFacade().isAStateVertex(port)) {
 130  0
             return new ArrayList(Model.getFacade().getIncomings(port));
 131  
         }
 132  0
         LOG.debug("TODO: getInEdges of MState");
 133  0
         return Collections.EMPTY_LIST;
 134  
     }
 135  
 
 136  
     /*
 137  
      * @see org.tigris.gef.graph.GraphModel#getOutEdges(java.lang.Object)
 138  
      */
 139  
     public List getOutEdges(Object port) {
 140  0
         if (Model.getFacade().isAStateVertex(port)) {
 141  0
             return new ArrayList(Model.getFacade().getOutgoings(port));
 142  
         }
 143  0
         LOG.debug("TODO: getOutEdges of MState");
 144  0
         return Collections.EMPTY_LIST;
 145  
     }
 146  
 
 147  
     ////////////////////////////////////////////////////////////////
 148  
     // MutableGraphModel implementation
 149  
 
 150  
     /*
 151  
      * @see org.tigris.gef.graph.MutableGraphModel#canAddNode(java.lang.Object)
 152  
      */
 153  
     public boolean canAddNode(Object node) {
 154  0
         if (node == null 
 155  
                 || !Model.getFacade().isAModelElement(node)
 156  
                 || containsNode(node)) {
 157  0
             return false;
 158  
         }
 159  
 
 160  0
         if (Model.getFacade().isAComment(node)) {
 161  0
             return true;
 162  
         }
 163  
         
 164  0
         if (Model.getFacade().isAStateVertex(node)
 165  
                 || Model.getFacade().isAPartition(node)) {
 166  
             /*
 167  
              * The next solves issue 3665: Do not allow addition of an element
 168  
              * to a statemachine that is contained by a statemachine other than
 169  
              * the one represented by this diagram.
 170  
              */
 171  0
             Object nodeMachine =
 172  
                 Model.getStateMachinesHelper().getStateMachine(node);
 173  0
             if (nodeMachine == null || nodeMachine == getMachine()) {
 174  0
                 return true;
 175  
             }
 176  
         }
 177  
 
 178  0
         return false;
 179  
     }
 180  
 
 181  
     /*
 182  
      * @see org.tigris.gef.graph.MutableGraphModel#canAddEdge(java.lang.Object)
 183  
      */
 184  
     public boolean canAddEdge(Object edge) {
 185  0
         if (super.canAddEdge(edge)) {
 186  0
             return true;
 187  
         }
 188  0
         if (edge == null) {
 189  0
             return false;
 190  
         }
 191  0
         if (containsEdge(edge)) {
 192  0
             return false;
 193  
         }
 194  
         
 195  0
         Object end0 = null;
 196  0
         Object end1 = null;
 197  
 
 198  0
         if (Model.getFacade().isATransition(edge)) {
 199  0
             end0 = Model.getFacade().getSource(edge);
 200  0
             end1 = Model.getFacade().getTarget(edge);
 201  0
         } else if (edge instanceof CommentEdge) {
 202  0
             end0 = ((CommentEdge) edge).getSource();
 203  0
             end1 = ((CommentEdge) edge).getDestination();
 204  
         } else {
 205  0
             return false;
 206  
         }
 207  
 
 208  
         // Both ends must be defined and nodes that are on the graph already.
 209  0
         if (end0 == null || end1 == null) {
 210  0
             LOG.error("Edge rejected. Its ends are not attached to anything");
 211  0
             return false;
 212  
         }
 213  
 
 214  0
         if (!containsNode(end0)
 215  
                 && !containsEdge(end0)) {
 216  0
             LOG.error("Edge rejected. Its source end is attached to "
 217  
                     + end0
 218  
                     + " but this is not in the graph model");
 219  0
             return false;
 220  
         }
 221  0
         if (!containsNode(end1)
 222  
                 && !containsEdge(end1)) {
 223  0
             LOG.error("Edge rejected. Its destination end is attached to "
 224  
                     + end1
 225  
                     + " but this is not in the graph model");
 226  0
             return false;
 227  
         }
 228  
 
 229  0
         return true;
 230  
     }
 231  
 
 232  
     /*
 233  
      * @see org.tigris.gef.graph.MutableGraphModel#addNode(java.lang.Object)
 234  
      */
 235  
     public void addNode(Object node) {
 236  0
         LOG.debug("adding statechart/activity diagram node: " + node);
 237  0
         if (!canAddNode(node)) {
 238  0
             return;
 239  
         }
 240  0
         if (containsNode(node)) {
 241  0
             return;
 242  
         }
 243  
 
 244  0
         getNodes().add(node);
 245  
 
 246  0
         if (Model.getFacade().isAStateVertex(node)) {
 247  0
             Object top = Model.getStateMachinesHelper().getTop(getMachine());
 248  0
             Model.getStateMachinesHelper().addSubvertex(top, node);
 249  
         }
 250  
 
 251  0
         fireNodeAdded(node);
 252  0
     }
 253  
 
 254  
     /*
 255  
      * @see org.tigris.gef.graph.MutableGraphModel#addEdge(java.lang.Object)
 256  
      */
 257  
     public void addEdge(Object edge) {
 258  0
         LOG.debug("adding statechart/activity diagram edge!!!!!!");
 259  0
         if (edge == null) {
 260  0
             throw new IllegalArgumentException("Cannot add a null edge");
 261  
         }
 262  
 
 263  0
         if (getDestPort(edge) == null || getSourcePort(edge) == null) {
 264  0
             throw new IllegalArgumentException(
 265  
                     "The source and dest port should be provided on an edge");
 266  
         }
 267  
 
 268  0
         if (LOG.isInfoEnabled()) {
 269  0
             LOG.info("Adding an edge of type "
 270  
                    + edge.getClass().getName()
 271  
                    + " to class diagram.");
 272  
         }
 273  
 
 274  0
         if (!canAddEdge(edge)) {
 275  0
             LOG.info("Attempt to add edge rejected");
 276  0
             return;
 277  
         }
 278  
         
 279  0
         getEdges().add(edge);
 280  
         
 281  0
         fireEdgeAdded(edge);
 282  0
     }
 283  
 
 284  
     /*
 285  
      * @see org.tigris.gef.graph.MutableGraphModel#addNodeRelatedEdges(java.lang.Object)
 286  
      */
 287  
     public void addNodeRelatedEdges(Object node) {
 288  0
         super.addNodeRelatedEdges(node);
 289  
 
 290  0
         if (Model.getFacade().isAStateVertex(node)) {
 291  0
             Collection transen = 
 292  
                 new ArrayList(Model.getFacade().getOutgoings(node));
 293  0
             transen.addAll(Model.getFacade().getIncomings(node));
 294  0
             Iterator iter = transen.iterator();
 295  0
             while (iter.hasNext()) {
 296  0
                 Object dep = /* (MTransition) */iter.next();
 297  0
                 if (canAddEdge(dep)) {
 298  0
                     addEdge(dep);
 299  
                 }
 300  0
             }
 301  
         }
 302  0
     }
 303  
 
 304  
     /*
 305  
      * @see org.tigris.gef.graph.MutableGraphModel#canConnect(java.lang.Object,
 306  
      *      java.lang.Object)
 307  
      */
 308  
     public boolean canConnect(Object fromPort, Object toPort) {
 309  0
         if (!(Model.getFacade().isAStateVertex(fromPort))) {
 310  0
             LOG.error("internal error not from sv");
 311  0
             return false;
 312  
         }
 313  0
         if (!(Model.getFacade().isAStateVertex(toPort))) {
 314  0
             LOG.error("internal error not to sv");
 315  0
             return false;
 316  
         }
 317  
 
 318  0
         if (Model.getFacade().isAFinalState(fromPort)) {
 319  0
             return false;
 320  
         }
 321  0
         if (Model.getFacade().isAPseudostate(toPort)) {
 322  0
             if ((Model.getPseudostateKind().getInitial()).equals(
 323  
                     Model.getFacade().getKind(toPort))) {
 324  0
                 return false;
 325  
             }
 326  
         }
 327  0
         return true;
 328  
     }
 329  
 
 330  
     /*
 331  
      * @see org.tigris.gef.graph.MutableGraphModel#connect(java.lang.Object,
 332  
      *      java.lang.Object, java.lang.Class)
 333  
      */
 334  
     public Object connect(Object fromPort, Object toPort,
 335  
                           Object edgeClass) {
 336  
 
 337  0
         if (Model.getFacade().isAFinalState(fromPort)) {
 338  0
             return null;
 339  
         }
 340  
 
 341  0
         if (Model.getFacade().isAPseudostate(toPort)
 342  
                 && Model.getPseudostateKind().getInitial().equals(
 343  
                         Model.getFacade().getKind(toPort))) {
 344  0
             return null;
 345  
         }
 346  
 
 347  0
         if (Model.getMetaTypes().getTransition().equals(edgeClass)) {
 348  0
             Object tr = null;
 349  0
             tr =
 350  
                 Model.getStateMachinesFactory()
 351  
                     .buildTransition(fromPort, toPort);
 352  0
             if (canAddEdge(tr)) {
 353  0
                 addEdge(tr);
 354  
             } else {
 355  0
                 ProjectManager.getManager().getCurrentProject().moveToTrash(tr);
 356  0
                 tr = null;
 357  
             }
 358  0
             return tr;
 359  0
         } else if (edgeClass == CommentEdge.class) {
 360  
             try {
 361  0
                 Object connection =
 362  
                     buildConnection(
 363  
                             edgeClass, fromPort, null, toPort, null, null,
 364  
                             ProjectManager.getManager().getCurrentProject()
 365  
                             .getModel());
 366  0
                 addEdge(connection);
 367  0
                 return connection;
 368  0
             } catch (Exception ex) {
 369  0
                 LOG.error("buildConnection() failed", ex);
 370  
             }
 371  0
             return null;
 372  
         } else {
 373  0
             LOG.debug("wrong kind of edge in StateDiagram connect3 "
 374  
                     + edgeClass);
 375  0
             return null;
 376  
         }
 377  
     }
 378  
 
 379  
     ////////////////////////////////////////////////////////////////
 380  
     // VetoableChangeListener implementation
 381  
 
 382  
     /*
 383  
      * @see java.beans.VetoableChangeListener#vetoableChange(java.beans.PropertyChangeEvent)
 384  
      */
 385  
     public void vetoableChange(PropertyChangeEvent pce) {
 386  
         //throws PropertyVetoException
 387  
 
 388  0
         if ("ownedElement".equals(pce.getPropertyName())) {
 389  0
             Collection oldOwned = (Collection) pce.getOldValue();
 390  0
             Object eo = /* (MElementImport) */pce.getNewValue();
 391  0
             Object me = Model.getFacade().getModelElement(eo);
 392  0
             if (oldOwned.contains(eo)) {
 393  0
                 LOG.debug("model removed " + me);
 394  0
                 if (Model.getFacade().isAState(me)) {
 395  0
                     removeNode(me);
 396  
                 }
 397  0
                 if (Model.getFacade().isAPseudostate(me)) {
 398  0
                     removeNode(me);
 399  
                 }
 400  0
                 if (Model.getFacade().isATransition(me)) {
 401  0
                     removeEdge(me);
 402  
                 }
 403  
             } else {
 404  0
                 LOG.debug("model added " + me);
 405  
             }
 406  
         }
 407  0
     }
 408  
 
 409  
     /**
 410  
      * The UID.
 411  
      */
 412  
     static final long serialVersionUID = -8056507319026044174L;
 413  
 
 414  
     /**
 415  
      * @param newNode
 416  
      *            this is the new node that one of the ends is dragged to.
 417  
      * @param oldNode
 418  
      *            this is the existing node that is already connected.
 419  
      * @param edge
 420  
      *            this is the edge that is being dragged/rerouted
 421  
      * @return true if a transition is being rerouted between two states.
 422  
      */
 423  
     public boolean canChangeConnectedNode(Object newNode, Object oldNode,
 424  
             Object edge) {
 425  
         // prevent no changes...
 426  0
         if (newNode == oldNode) {
 427  0
             return false;
 428  
         }
 429  
 
 430  
         // check parameter types:
 431  0
         if (!(Model.getFacade().isAState(newNode)
 432  
               || Model.getFacade().isAState(oldNode)
 433  
               || Model.getFacade().isATransition(edge))) {
 434  0
             return false;
 435  
         }
 436  
 
 437  
         // it's not allowed to move a transition
 438  
         // so that it will go from a composite to its substate
 439  
         // nor vice versa. See issue 2865.
 440  0
         Object otherSideNode = Model.getFacade().getSource(edge);
 441  0
         if (otherSideNode == oldNode) {
 442  0
             otherSideNode = Model.getFacade().getTarget(edge);
 443  
         }
 444  0
         if (Model.getFacade().isACompositeState(newNode)
 445  
                 && Model.getStateMachinesHelper().getAllSubStates(newNode)
 446  
                                                     .contains(otherSideNode)) {
 447  0
             return false;
 448  
         }
 449  
 
 450  0
         return true;
 451  
     }
 452  
 
 453  
     /**
 454  
      * Reroutes the connection to the old node to be connected to the new node.
 455  
      *
 456  
      * @param newNode
 457  
      *            this is the new node that one of the ends is dragged to.
 458  
      * @param oldNode
 459  
      *            this is the existing node that is already connected.
 460  
      * @param edge
 461  
      *            this is the edge that is being dragged/rerouted
 462  
      * @param isSource
 463  
      *            tells us which end is being rerouted.
 464  
      */
 465  
     public void changeConnectedNode(Object newNode, Object oldNode,
 466  
             Object edge, boolean isSource) {
 467  
 
 468  0
         if (isSource) {
 469  0
             Model.getStateMachinesHelper().setSource(edge, newNode);
 470  
         } else {
 471  0
             Model.getCommonBehaviorHelper().setTarget(edge, newNode);
 472  
         }
 473  
 
 474  0
     }
 475  
 
 476  
     /*
 477  
      * @see org.argouml.uml.diagram.UMLMutableGraphSupport#isRemoveFromDiagramAllowed(Collection)
 478  
      */
 479  
     public boolean isRemoveFromDiagramAllowed(Collection figs) {
 480  
         /* If nothing is selected, then not allowed to remove it. */
 481  18
         if (figs.isEmpty()) {
 482  18
             return false;
 483  
         }
 484  0
         Iterator i = figs.iterator();
 485  0
         while (i.hasNext()) {
 486  0
             Object obj = i.next();
 487  0
             if (!(obj instanceof Fig)) {
 488  0
                 return false;
 489  
             }
 490  0
             Object uml = ((Fig) obj).getOwner();
 491  
             /* If a UML object is found, you can not remove selected elms. */
 492  0
             if (uml != null) {
 493  0
                 return false;
 494  
             }
 495  0
         }
 496  
         /* If only Figs without owner are selected, then you can remove them! */
 497  0
         return true;
 498  
     }
 499  
 
 500  
 
 501  
 } /* end class StateDiagramGraphModel */