Coverage Report - org.argouml.uml.diagram.static_structure.ui.FigClassifierBox
 
Classes in this File Line Coverage Branch Coverage Complexity
FigClassifierBox
0%
0/131
0%
0/86
3.087
 
 1  
 /* $Id: FigClassifierBox.java 17739 2010-01-09 08:39:10Z 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  
  *    Bob Tarling
 11  
  *    Michiel van der Wulp
 12  
  *******************************************************************************
 13  
  *
 14  
  * Some portions of this file were previously release using the BSD License:
 15  
  */
 16  
 // $Id: FigClassifierBox.java 17739 2010-01-09 08:39:10Z bobtarling $
 17  
 // Copyright (c) 1996-2009 The Regents of the University of California. All
 18  
 // Rights Reserved. Permission to use, copy, modify, and distribute this
 19  
 // software and its documentation without fee, and without a written
 20  
 // agreement is hereby granted, provided that the above copyright notice
 21  
 // and this paragraph appear in all copies.  This software program and
 22  
 // documentation are copyrighted by The Regents of the University of
 23  
 // California. The software program and documentation are supplied "AS
 24  
 // IS", without any accompanying services from The Regents. The Regents
 25  
 // does not warrant that the operation of the program will be
 26  
 // uninterrupted or error-free. The end-user understands that the program
 27  
 // was developed for research purposes and is advised not to rely
 28  
 // exclusively on the program for any reason.  IN NO EVENT SHALL THE
 29  
 // UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
 30  
 // SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS,
 31  
 // ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
 32  
 // THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
 33  
 // SUCH DAMAGE. THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY
 34  
 // WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 35  
 // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
 36  
 // PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF
 37  
 // CALIFORNIA HAS NO OBLIGATIONS TO PROVIDE MAINTENANCE, SUPPORT,
 38  
 // UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
 39  
 
 40  
 package org.argouml.uml.diagram.static_structure.ui;
 41  
 
 42  
 import java.awt.Rectangle;
 43  
 import java.awt.event.MouseEvent;
 44  
 import java.beans.PropertyChangeEvent;
 45  
 import java.util.HashSet;
 46  
 import java.util.Iterator;
 47  
 import java.util.List;
 48  
 import java.util.Set;
 49  
 import java.util.Vector;
 50  
 
 51  
 import javax.swing.Action;
 52  
 
 53  
 import org.argouml.model.AddAssociationEvent;
 54  
 import org.argouml.model.AssociationChangeEvent;
 55  
 import org.argouml.model.AttributeChangeEvent;
 56  
 import org.argouml.model.Model;
 57  
 import org.argouml.model.RemoveAssociationEvent;
 58  
 import org.argouml.model.UmlChangeEvent;
 59  
 import org.argouml.ui.ActionCreateContainedModelElement;
 60  
 import org.argouml.ui.ArgoJMenu;
 61  
 import org.argouml.uml.diagram.DiagramSettings;
 62  
 import org.argouml.uml.diagram.OperationsCompartmentContainer;
 63  
 import org.argouml.uml.diagram.ui.ActionAddNote;
 64  
 import org.argouml.uml.diagram.ui.ActionCompartmentDisplay;
 65  
 import org.argouml.uml.diagram.ui.ActionEdgesDisplay;
 66  
 import org.argouml.uml.diagram.ui.FigAttributesCompartment;
 67  
 import org.argouml.uml.diagram.ui.FigCompartment;
 68  
 import org.argouml.uml.diagram.ui.FigCompartmentBox;
 69  
 import org.argouml.uml.diagram.ui.FigOperationsCompartment;
 70  
 import org.tigris.gef.base.Editor;
 71  
 import org.tigris.gef.base.Globals;
 72  
 import org.tigris.gef.base.Selection;
 73  
 import org.tigris.gef.presentation.Fig;
 74  
 
 75  
 /**
 76  
  * Class to display graphics for any UML Classifier in a diagram.<p>
 77  
  * 
 78  
  * This abstract Fig adds an Operations compartment.
 79  
  */
 80  
 public abstract class FigClassifierBox extends FigCompartmentBox
 81  
         implements OperationsCompartmentContainer {
 82  
 
 83  
     /**
 84  
      * The Fig for the operations compartment (if any).
 85  
      */
 86  
     private FigOperationsCompartment operationsFigCompartment;
 87  
     
 88  
     private Rectangle getDefaultBounds() {
 89  
         // this rectangle marks the operation section; all operations
 90  
         // are inside it
 91  0
         Rectangle bounds = new Rectangle(DEFAULT_COMPARTMENT_BOUNDS);
 92  
         // 2nd compartment, so adjust Y appropriately
 93  0
         bounds.y = DEFAULT_COMPARTMENT_BOUNDS.y + ROWHEIGHT + 1;
 94  0
         return bounds;
 95  
     }
 96  
 
 97  
     /**
 98  
      * Construct a Fig with owner, bounds, and settings.
 99  
      * 
 100  
      * @param owner the model element that owns this fig
 101  
      * @param bounds the rectangle defining the bounds
 102  
      * @param settings the rendering settings
 103  
      */
 104  
     public FigClassifierBox(Object owner, Rectangle bounds,
 105  
             DiagramSettings settings) {
 106  0
         super(owner, bounds, settings);
 107  0
         operationsFigCompartment = new FigOperationsCompartment(
 108  
                 owner, 
 109  
                 getDefaultBounds(),
 110  
                 getSettings());
 111  0
     }
 112  
 
 113  
     /*
 114  
      * @see java.lang.Object#clone()
 115  
      */
 116  
     public Object clone() {
 117  0
         FigClassifierBox figClone = (FigClassifierBox) super.clone();
 118  0
         Iterator thisIter = this.getFigs().iterator();
 119  0
         while (thisIter.hasNext()) {
 120  0
             Fig thisFig = (Fig) thisIter.next();
 121  0
             if (thisFig == operationsFigCompartment) {
 122  0
                 figClone.operationsFigCompartment = (FigOperationsCompartment) thisFig;
 123  0
                 return figClone;
 124  
             }
 125  0
         }
 126  0
         return figClone;
 127  
     }
 128  
 
 129  
     /**
 130  
      * @deprecated by Bob Tarling in 0.29.3 use
 131  
      * updateCompartment(Model.getMetaTypes().getAttribute())
 132  
      */
 133  
     protected void updateOperations() {
 134  0
         if (!isOperationsVisible()) {
 135  0
             return;
 136  
         }
 137  0
         operationsFigCompartment.populate();
 138  
 
 139  0
         setBounds(getBounds());
 140  0
         damage();
 141  0
     }
 142  
     
 143  
     /*
 144  
      * @see org.argouml.uml.diagram.ui.FigNodeModelElement#renderingChanged()
 145  
      */
 146  
     public void renderingChanged() {
 147  0
         super.renderingChanged();
 148  
         // TODO: We should be able to just call renderingChanged on the child
 149  
         // figs here instead of doing an updateOperations...
 150  0
         updateOperations();
 151  
         
 152  
         // TODO: Taken from FigClassifierBoxWithAttribute to handle events
 153  
         // on an attribute. All this event handling should eventually be moved
 154  
         // to the compartment Fig for attributes
 155  0
         if (isAttributesVisible()) {
 156  
             // TODO: We shouldn't actually have to do all this work
 157  0
             updateCompartment(Model.getMetaTypes().getAttribute());
 158  
         }
 159  0
     }
 160  
     
 161  
     /**
 162  
      * We are getting events we don't want. Filter them out.
 163  
      * TODO: Can we instruct the model event pump not to send these in the
 164  
      * first place? See defect 5095.
 165  
      * @param event the event
 166  
      */
 167  
     public void propertyChange(PropertyChangeEvent event) {
 168  0
         if (event.getPropertyName().equals("generalization")
 169  
                 && Model.getFacade().isAGeneralization(event.getOldValue())) {
 170  0
             return;
 171  0
         } else if (event.getPropertyName().equals("association")
 172  
                 && Model.getFacade().isAAssociationEnd(event.getOldValue())) {
 173  0
             return;
 174  0
         } else if (event.getPropertyName().equals("supplierDependency")
 175  
                 && Model.getFacade().isAUsage(event.getOldValue())) {
 176  0
             return;
 177  0
         } else if (event.getPropertyName().equals("clientDependency")
 178  
                 && Model.getFacade().isAAbstraction(event.getOldValue())) {
 179  0
             return;
 180  
         }
 181  
         
 182  0
         super.propertyChange(event);
 183  0
     }
 184  
 
 185  
     protected void updateLayout(UmlChangeEvent event) {
 186  0
         super.updateLayout(event);
 187  0
         if (event instanceof AssociationChangeEvent 
 188  
                 && getOwner().equals(event.getSource())) {
 189  0
             Object o = null;
 190  0
             if (event instanceof AddAssociationEvent) {
 191  0
                 o = event.getNewValue();
 192  0
             } else if (event instanceof RemoveAssociationEvent) {
 193  0
                 o = event.getOldValue();
 194  
             }
 195  0
             if (Model.getFacade().isAOperation(o) 
 196  
                     || Model.getFacade().isAReception(o)) {
 197  0
                 updateOperations();
 198  
             }
 199  
         }
 200  
         
 201  
         // TODO: Taken from FigClassifierBoxWithAttribute to handle events
 202  
         // on an attribute. All this event handling should eventually be moved
 203  
         // to the compartment Fig for attributes
 204  0
         if (Model.getFacade().isAAttribute(getOwner())) {
 205  0
             if (event instanceof AttributeChangeEvent) {
 206  0
                 Object source = event.getSource();
 207  0
                 if (Model.getFacade().isAAttribute(source)) {
 208  
                     // TODO: We just need to get someone to re-render a single
 209  
                     // line of text which represents the element here, but I'm
 210  
                     // not sure how to do that. - tfm
 211  
                     // TODO: Bob replies - we shouldn't be interested in this
 212  
                     // event here. The FigFeature (or its notation) should be
 213  
                     // listen for change and the FigFeature should be update
 214  
                     // from that.
 215  0
                     updateCompartment(Model.getMetaTypes().getAttribute());
 216  
                 }
 217  0
             } else if (event instanceof AssociationChangeEvent 
 218  
                     && getOwner().equals(event.getSource())) {
 219  0
                 Object o = null;
 220  0
                 if (event instanceof AddAssociationEvent) {
 221  0
                     o = event.getNewValue();
 222  0
                 } else if (event instanceof RemoveAssociationEvent) {
 223  0
                     o = event.getOldValue();
 224  
                 }
 225  0
                 if (Model.getFacade().isAAttribute(o)) {
 226  
                     // TODO: Bob says - we should not be listening here for
 227  
                     // addition and removal of attributes. This should be done in
 228  
                     // FigAttributesCompartment.
 229  0
                     updateCompartment(Model.getMetaTypes().getAttribute());
 230  
                 }
 231  
             }
 232  
         }
 233  0
     }
 234  
     
 235  
     @Override
 236  
     protected void updateListeners(Object oldOwner, Object newOwner) {
 237  
        
 238  0
         if (isAttributesVisible()) {
 239  0
             Set<Object[]> listeners = new HashSet<Object[]>();
 240  
 
 241  
             // Collect the set of model elements that we want to listen to
 242  0
             if (newOwner != null) {
 243  
                 // TODO: Because we get called on each and every change event, when
 244  
                 // the model is in a state of flux, we'll often get an
 245  
                 // InvalidElementException before we finish this collection. The
 246  
                 // only saving grace is that we're called SO many times that on the
 247  
                 // last time, things should be stable again and we'll get a good set
 248  
                 // of elements for the final update.  We need a better mechanism.
 249  
                 
 250  
                 // add the listeners to the newOwner
 251  0
                 listeners.add(new Object[] {newOwner, null});
 252  
                 
 253  
                 // and its stereotypes
 254  
                 // TODO: Aren't stereotypes handled elsewhere?
 255  
                 for (Object stereotype 
 256  0
                         : Model.getFacade().getStereotypes(newOwner)) {
 257  0
                     listeners.add(new Object[] {stereotype, null});
 258  
                 }
 259  
 
 260  
                 // and its features
 261  0
                 for (Object feat : Model.getFacade().getFeatures(newOwner)) {
 262  0
                     listeners.add(new Object[] {feat, null});
 263  
                     // and the stereotypes of its features
 264  
                     for (Object stereotype 
 265  0
                             : Model.getFacade().getStereotypes(feat)) {
 266  0
                         listeners.add(new Object[] {stereotype, null});
 267  
                     }
 268  
                     // and the parameter of its operations
 269  0
                     if (Model.getFacade().isAOperation(feat)) {
 270  0
                         for (Object param : Model.getFacade().getParameters(feat)) {
 271  0
                             listeners.add(new Object[] {param, null});
 272  
                         }
 273  
                     }
 274  
                 }
 275  
             }
 276  
             
 277  
             // Update the listeners to match the desired set using the minimal
 278  
             // update facility
 279  0
             updateElementListeners(listeners);
 280  0
         } else {
 281  0
             super.updateListeners(oldOwner, newOwner);
 282  
         }
 283  0
     }
 284  
     
 285  
     /**
 286  
      * Updates a compartment box. Called from updateLayout if there is
 287  
      * a model event effecting the attributes/operations and from
 288  
      * renderingChanged in all cases.
 289  
      * TODO: The above statement means that the entire contents of the
 290  
      * compartments are being rebuilt whenever an add/remove
 291  
      * of an attribute, operation or a reception is detected. It would be
 292  
      * better to have compartments listen for add and remove events
 293  
      * and make minimum change rather than entirely rebuild. 
 294  
      * Remark MVW: This is a bit exaggerated, since the populate() 
 295  
      * method is already heavily optimized.
 296  
      */
 297  
     protected void updateCompartment(Object metaType) {
 298  0
         FigCompartment fc = getCompartment(metaType);
 299  0
         if (!fc.isVisible()) {
 300  0
             return;
 301  
         }
 302  0
         fc.populate();
 303  
     
 304  
         // TODO: make setBounds, calcBounds and updateBounds consistent
 305  0
         setBounds(getBounds());
 306  0
     }
 307  
 
 308  
     /**
 309  
      * @return The graphics for the UML operations (if any).
 310  
      * @deprecated in 0.29.3 use
 311  
      * getCompartment(Model.getUmlFactory(Model.getMetaTypes(),getOperation()))
 312  
      * to determine if an operation compartment exists and return it.
 313  
      * The operationsCompartment should be created by the concrete class
 314  
      */
 315  
     protected FigOperationsCompartment getOperationsFig() {
 316  0
         return operationsFigCompartment;
 317  
     }
 318  
 
 319  
     /**
 320  
      * @deprecated by Bob Tarling in 0.29.3 use
 321  
      * getCompartment(Model.getMetaTypes().getOperation()).getBounds()
 322  
      * @return the bounds
 323  
      */
 324  
     public Rectangle getOperationsBounds() {
 325  0
         return operationsFigCompartment.getBounds();
 326  
     }
 327  
 
 328  
     /**
 329  
      * @deprecated by Bob Tarling in 0.29.2 use
 330  
      * isCompartmentVisible(Model.getMetaTypes().getOperation())
 331  
      * @return the visibility
 332  
      */
 333  
     public boolean isOperationsVisible() {
 334  0
         return operationsFigCompartment != null && operationsFigCompartment.isVisible();
 335  
     }
 336  
 
 337  
     /**
 338  
      * TODO: Should not be on this class as we don't know if we'll have
 339  
      * operations
 340  
      * @param isVisible true if the operation compartment is visible
 341  
      * @deprecated by Bob Tarling in 0.29.2 use setCompartmentVisible
 342  
      */
 343  
     public void setOperationsVisible(boolean isVisible) {
 344  0
         setCompartmentVisible(operationsFigCompartment, isVisible);
 345  0
     }
 346  
     
 347  
     /**
 348  
      * @return The graphics for the UML attributes (if any).
 349  
      * @deprecated in 0.29.1 use
 350  
      * getCompartment(Model.getUmlFactory(Model.getMetaTypes(),getAttribute()))
 351  
      * to determine if an attribute compartment exists and return it.
 352  
      * The attributesCompartment should be created by the concrete class
 353  
      */
 354  
     protected FigAttributesCompartment getAttributesFig() {
 355  0
         FigCompartment fc = getCompartment(Model.getMetaTypes().getAttribute());
 356  0
         return (FigAttributesCompartment) fc;
 357  
     }
 358  
     
 359  
     /**
 360  
      * @deprecated by Bob Tarling in 0.29.2 use
 361  
      * getCompartment(Model.getMetaTypes().getAttribute()).getBounds()
 362  
      * @return the bounds
 363  
      */
 364  
     @Deprecated
 365  
     public Rectangle getAttributesBounds() {
 366  0
         return getAttributesFig().getBounds();
 367  
     }
 368  
 
 369  
     /**
 370  
      * @deprecated by Bob Tarling in 0.29.2 use
 371  
      * isCompartmentVisible(Model.getMetaTypes().getAttribute())
 372  
      * @return the visibility
 373  
      */
 374  
     @Deprecated
 375  
     public boolean isAttributesVisible() {
 376  0
         FigCompartment fc = getCompartment(Model.getMetaTypes().getAttribute());
 377  0
         return fc != null && fc.isVisible();
 378  
     }
 379  
     
 380  
     /**
 381  
      * TODO: Should not be on this class as we don't know if we'll have
 382  
      * attributes
 383  
      * @param isVisible true if the attribute compartment is visible
 384  
      * @deprecated by Bob Tarling in 0.29.2 use setCompartmentVisible
 385  
      */
 386  
     public void setAttributesVisible(boolean isVisible) {
 387  0
         final FigCompartment afc =
 388  
             getCompartment(Model.getMetaTypes().getAttribute());
 389  0
         setCompartmentVisible(afc, isVisible);
 390  0
     }
 391  
     
 392  
     /*
 393  
      * @see org.tigris.gef.presentation.Fig#translate(int, int)
 394  
      */
 395  
     public void translate(int dx, int dy) {
 396  0
         super.translate(dx, dy);
 397  0
         Editor ce = Globals.curEditor();
 398  0
         if (ce != null) {
 399  0
             Selection sel = ce.getSelectionManager().findSelectionFor(this);
 400  
             // TODO" What is the purpose of this? Why do we hide buttons here?
 401  
             // Presumably if so we should not assume SelectionClass
 402  0
             if (sel instanceof SelectionClass) {
 403  0
                 ((SelectionClass) sel).hideButtons();
 404  
             }
 405  
         }
 406  0
     }
 407  
 
 408  
     /**
 409  
      * Build a collection of menu items relevant for a right-click
 410  
      * popup menu on an Interface.
 411  
      *
 412  
      * @param     me     a mouse event
 413  
      * @return           a collection of menu items
 414  
      */
 415  
     public Vector getPopUpActions(MouseEvent me) {
 416  0
         Vector popUpActions = super.getPopUpActions(me);
 417  
     
 418  
         // Add ...
 419  0
         ArgoJMenu addMenu = buildAddMenu();
 420  0
         popUpActions.add(
 421  
                 popUpActions.size() - getPopupAddOffset(),
 422  
                 addMenu);
 423  
 
 424  
         // Modifier ...
 425  0
         popUpActions.add(
 426  
                 popUpActions.size() - getPopupAddOffset(),
 427  
                 buildModifierPopUp());
 428  
     
 429  
         // Visibility ...
 430  0
         popUpActions.add(
 431  
                 popUpActions.size() - getPopupAddOffset(),
 432  
                 buildVisibilityPopUp());
 433  
     
 434  0
         return popUpActions;
 435  
     }
 436  
 
 437  
     protected ArgoJMenu buildShowPopUp() {
 438  0
         ArgoJMenu showMenu = super.buildShowPopUp();
 439  
 
 440  0
         Iterator i = ActionCompartmentDisplay.getActions().iterator();
 441  0
         while (i.hasNext()) {
 442  0
             showMenu.add((Action) i.next());
 443  
         }
 444  0
         return showMenu;
 445  
     }
 446  
 
 447  
     protected ArgoJMenu buildAddMenu() {
 448  0
         ArgoJMenu addMenu = new ArgoJMenu("menu.popup.add");
 449  
         
 450  0
         List<FigCompartment> comps = getCompartments();
 451  0
         for (FigCompartment comp : comps) {
 452  0
             final Object metaType = comp.getCompartmentType();
 453  0
             Action addAction = new ActionCreateContainedModelElement(metaType, getOwner());
 454  0
             addAction.setEnabled(isSingleTarget());
 455  0
             addMenu.insert(addAction, 0);
 456  0
         }
 457  0
         addMenu.add(new ActionAddNote());
 458  0
         addMenu.add(ActionEdgesDisplay.getShowEdges());
 459  0
         addMenu.add(ActionEdgesDisplay.getHideEdges());
 460  0
         return addMenu;
 461  
     }
 462  
 
 463  
     /**
 464  
      * USED BY PGML.tee.
 465  
      * TODO We should loop round the compartments to build this string. That
 466  
      * way we have no attribute/operation knowledge at this level.
 467  
      * @return the class name and bounds together with compartment
 468  
      * visibility.
 469  
      */
 470  
     public String classNameAndBounds() {
 471  0
         String classNameAndBounds =  super.classNameAndBounds()
 472  
             + "operationsVisible=" + isOperationsVisible() + ";";
 473  0
         FigCompartment fc = getCompartment(Model.getMetaTypes().getAttribute());
 474  0
         if (fc != null) {
 475  0
             classNameAndBounds += 
 476  
                 "attributesVisible=" + fc.isVisible() + ";";
 477  
         }
 478  0
         return classNameAndBounds;
 479  
     }
 480  
 
 481  
     
 482  
     protected Object buildModifierPopUp() {
 483  0
         return buildModifierPopUp(ABSTRACT | LEAF | ROOT);
 484  
     }
 485  
 }