Coverage Report - org.argouml.uml.diagram.ui.FigNodeModelElement
 
Classes in this File Line Coverage Branch Coverage Complexity
FigNodeModelElement
7%
57/778
2%
11/490
3.124
FigNodeModelElement$1
0%
0/7
0%
0/2
3.124
FigNodeModelElement$SelectionDefaultClarifiers
0%
0/9
N/A
3.124
 
 1  
 /* $Id: FigNodeModelElement.java 18859 2010-11-29 21:37:03Z mvw $
 2  
  *****************************************************************************
 3  
  * Copyright (c) 2009-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  
  *    Thomas Neustupny
 11  
  *    Bob Tarling
 12  
  *    Michiel van der Wulp
 13  
  *****************************************************************************
 14  
  *
 15  
  * Some portions of this file was previously release using the BSD License:
 16  
  */
 17  
 
 18  
 // Copyright (c) 1996-2009 The Regents of the University of California. All
 19  
 // Rights Reserved. Permission to use, copy, modify, and distribute this
 20  
 // software and its documentation without fee, and without a written
 21  
 // agreement is hereby granted, provided that the above copyright notice
 22  
 // and this paragraph appear in all copies.  This software program and
 23  
 // documentation are copyrighted by The Regents of the University of
 24  
 // California. The software program and documentation are supplied "AS
 25  
 // IS", without any accompanying services from The Regents. The Regents
 26  
 // does not warrant that the operation of the program will be
 27  
 // uninterrupted or error-free. The end-user understands that the program
 28  
 // was developed for research purposes and is advised not to rely
 29  
 // exclusively on the program for any reason.  IN NO EVENT SHALL THE
 30  
 // UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
 31  
 // SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS,
 32  
 // ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
 33  
 // THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
 34  
 // SUCH DAMAGE. THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY
 35  
 // WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 36  
 // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
 37  
 // PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF
 38  
 // CALIFORNIA HAS NO OBLIGATIONS TO PROVIDE MAINTENANCE, SUPPORT,
 39  
 // UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
 40  
 
 41  
 package org.argouml.uml.diagram.ui;
 42  
 
 43  
 import java.awt.Dimension;
 44  
 import java.awt.Font;
 45  
 import java.awt.Graphics;
 46  
 import java.awt.Image;
 47  
 import java.awt.Rectangle;
 48  
 import java.awt.event.InputEvent;
 49  
 import java.awt.event.KeyEvent;
 50  
 import java.awt.event.KeyListener;
 51  
 import java.awt.event.MouseEvent;
 52  
 import java.awt.event.MouseListener;
 53  
 import java.beans.PropertyChangeEvent;
 54  
 import java.beans.PropertyChangeListener;
 55  
 import java.beans.PropertyVetoException;
 56  
 import java.beans.VetoableChangeListener;
 57  
 import java.util.ArrayList;
 58  
 import java.util.Collection;
 59  
 import java.util.HashSet;
 60  
 import java.util.Iterator;
 61  
 import java.util.List;
 62  
 import java.util.Set;
 63  
 import java.util.Vector;
 64  
 
 65  
 import javax.swing.Action;
 66  
 import javax.swing.Icon;
 67  
 import javax.swing.JMenu;
 68  
 import javax.swing.JSeparator;
 69  
 import javax.swing.SwingUtilities;
 70  
 
 71  
 import org.apache.log4j.Logger;
 72  
 import org.argouml.application.events.ArgoDiagramAppearanceEvent;
 73  
 import org.argouml.application.events.ArgoDiagramAppearanceEventListener;
 74  
 import org.argouml.application.events.ArgoEventPump;
 75  
 import org.argouml.application.events.ArgoEventTypes;
 76  
 import org.argouml.application.events.ArgoHelpEvent;
 77  
 import org.argouml.application.events.ArgoNotationEvent;
 78  
 import org.argouml.application.events.ArgoNotationEventListener;
 79  
 import org.argouml.cognitive.Designer;
 80  
 import org.argouml.cognitive.Highlightable;
 81  
 import org.argouml.cognitive.ToDoItem;
 82  
 import org.argouml.cognitive.ToDoList;
 83  
 import org.argouml.cognitive.ui.ActionGoToCritique;
 84  
 import org.argouml.i18n.Translator;
 85  
 import org.argouml.kernel.DelayedChangeNotify;
 86  
 import org.argouml.kernel.DelayedVChangeListener;
 87  
 import org.argouml.kernel.Owned;
 88  
 import org.argouml.kernel.Project;
 89  
 import org.argouml.model.AssociationChangeEvent;
 90  
 import org.argouml.model.AttributeChangeEvent;
 91  
 import org.argouml.model.DeleteInstanceEvent;
 92  
 import org.argouml.model.DiElement;
 93  
 import org.argouml.model.InvalidElementException;
 94  
 import org.argouml.model.Model;
 95  
 import org.argouml.model.UmlChangeEvent;
 96  
 import org.argouml.notation.Notation;
 97  
 import org.argouml.notation.NotationName;
 98  
 import org.argouml.notation.NotationProvider;
 99  
 import org.argouml.notation.NotationProviderFactory2;
 100  
 import org.argouml.notation.NotationRenderer;
 101  
 import org.argouml.notation.NotationSettings;
 102  
 import org.argouml.profile.FigNodeStrategy;
 103  
 import org.argouml.ui.ArgoJMenu;
 104  
 import org.argouml.ui.Clarifier;
 105  
 import org.argouml.ui.ContextActionFactoryManager;
 106  
 import org.argouml.ui.ProjectActions;
 107  
 import org.argouml.ui.UndoableAction;
 108  
 import org.argouml.ui.targetmanager.TargetManager;
 109  
 import org.argouml.uml.StereotypeUtility;
 110  
 import org.argouml.uml.diagram.ArgoDiagram;
 111  
 import org.argouml.uml.diagram.DiagramAppearance;
 112  
 import org.argouml.uml.diagram.DiagramElement;
 113  
 import org.argouml.uml.diagram.DiagramSettings;
 114  
 import org.argouml.uml.diagram.DiagramSettings.StereotypeStyle;
 115  
 import org.argouml.uml.diagram.PathContainer;
 116  
 import org.argouml.uml.ui.ActionDeleteModelElements;
 117  
 import org.argouml.util.IItemUID;
 118  
 import org.argouml.util.ItemUID;
 119  
 import org.tigris.gef.base.Diagram;
 120  
 import org.tigris.gef.base.Globals;
 121  
 import org.tigris.gef.base.Layer;
 122  
 import org.tigris.gef.base.LayerPerspective;
 123  
 import org.tigris.gef.base.Selection;
 124  
 import org.tigris.gef.graph.MutableGraphSupport;
 125  
 import org.tigris.gef.presentation.Fig;
 126  
 import org.tigris.gef.presentation.FigGroup;
 127  
 import org.tigris.gef.presentation.FigImage;
 128  
 import org.tigris.gef.presentation.FigNode;
 129  
 import org.tigris.gef.presentation.FigRect;
 130  
 import org.tigris.gef.presentation.FigText;
 131  
 
 132  
 /**
 133  
  * Abstract class to display diagram icons for UML ModelElements that
 134  
  * look like nodes and that have editable names and can be
 135  
  * resized.
 136  
  * <p>
 137  
  * NOTE: This will drop the ArgoNotationEventListener and 
 138  
  * ArgoDiagramAppearanceEventListener interfaces in the next release.  
 139  
  * The corresponding methods have been marked as deprecated.
 140  
  *
 141  
  * @author abonner
 142  
  */
 143  119
 public abstract class FigNodeModelElement
 144  
     extends FigNode
 145  
     implements
 146  
         VetoableChangeListener,
 147  
         DelayedVChangeListener,
 148  
         MouseListener,
 149  
         KeyListener,
 150  
         PropertyChangeListener,
 151  
         PathContainer,
 152  
         ArgoDiagramAppearanceEventListener,
 153  
         ArgoNotationEventListener,
 154  
         NotationRenderer,
 155  
         Highlightable,
 156  
         IItemUID,
 157  
         Clarifiable,
 158  
         ArgoFig,
 159  
         StereotypeStyled,
 160  
         DiagramElement,
 161  
         Owned {
 162  
 
 163  
 
 164  119
     private static final Logger LOG =
 165  
         Logger.getLogger(FigNodeModelElement.class);
 166  
 
 167  
     // TODO: There are lots and LOTS of magic numbers used in calculating 
 168  
     // positions and sizes.  Any time you see Figs being placed at 10,10 use
 169  
     // these constants instead.  If you can reliably interpret calculations,
 170  
     // you can factor them out of there as well.  Add additional constants
 171  
     // as needed to express other common factors - tfm 20081201
 172  
     
 173  
     /**
 174  
      * Default width for a node fig. 
 175  
      * Used to be 60 (up to V0.20), later (from V0.22) it was 90.
 176  
      * Now 64 to align to grid better.
 177  
      */
 178  
     protected static final int WIDTH = 64;
 179  
 
 180  
     /**
 181  
      * The default minimum height of the name fig, computed to allow room for
 182  
      * the Critics "clarifiers" (red squiggly line) with the default font. This
 183  
      * should really go away and be managed internally to the name figs and
 184  
      * fetched through getMinimumSize(). The final height can change based on
 185  
      * the font selected.
 186  
      */
 187  
     protected static final int NAME_FIG_HEIGHT = 21;
 188  
     
 189  
     /**
 190  
      * Padding to be used above and below the name.
 191  
      */
 192  
     protected static final int NAME_V_PADDING = 2;
 193  
     
 194  
     private DiElement diElement;
 195  
 
 196  
     private NotationProvider notationProviderName;
 197  
     
 198  
     /**
 199  
      * True if an instance is allowed to be
 200  
      * invisible. This is currently only set true by FigEdgePort.
 201  
      * TODO: FigEdgePort should be removed from the FigNodeModelElement
 202  
      * hierarchy and so the need for this removed.
 203  
      */
 204  1071
     protected boolean invisibleAllowed = false;
 205  
 
 206  
 
 207  
     /**
 208  
      * Needed for loading. Warning: if false, a too small size might look bad!
 209  
      */
 210  1071
     private boolean checkSize = true;
 211  
 
 212  
     /**
 213  
      * Offset from the end of the set of popup actions at which new items
 214  
      * should be inserted by concrete figures.
 215  
      * @See {@link #getPopUpActions(MouseEvent)}
 216  
      */
 217  
     private static int popupAddOffset;
 218  
 
 219  
     /**
 220  
      * Used for #buildModifierPopUp().
 221  
      */
 222  
     protected static final int ROOT = 1;
 223  
 
 224  
     /**
 225  
      * Used for #buildModifierPopUp().
 226  
      */
 227  
     protected static final int ABSTRACT = 2;
 228  
 
 229  
     /**
 230  
      * Used for #buildModifierPopUp().
 231  
      */
 232  
     protected static final int LEAF = 4;
 233  
 
 234  
     /**
 235  
      * Used for #buildModifierPopUp().
 236  
      */
 237  
     protected static final int ACTIVE = 8;
 238  
 
 239  
     private Fig bigPort;
 240  
 
 241  
     /**
 242  
      * use getNameFig() and setNameFig() to access the Figs.
 243  
      * Use getName() and setName() to just change the text.
 244  
      */
 245  
     private FigText nameFig;
 246  
 
 247  
     /**
 248  
      * use getter/setter
 249  
      * getStereotypeFig() and setStereoTypeFig() to access the Figs.
 250  
      * Use getStereotype() and setStereotype() to change stereotype
 251  
      * text.
 252  
      */
 253  
     private FigStereotypesGroup stereotypeFig;
 254  
 
 255  
     /**
 256  
      * The <code>FigProfileIcon</code> being currently displayed
 257  
      */
 258  
     private FigProfileIcon stereotypeFigProfileIcon;
 259  
 
 260  
     /**
 261  
      * Contains the figs of the floating stereotypes when viewed in 
 262  
      * <code>SmallIcon</code> mode.
 263  
      */
 264  1071
     private List<Fig> floatingStereotypes = new ArrayList<Fig>();
 265  
     
 266  
     /**
 267  
      * The current stereotype view, defaults to "textual".
 268  
      * 
 269  
      * @see DiagramAppearance#STEREOTYPE_VIEW_TEXTUAL
 270  
      * @see DiagramAppearance#STEREOTYPE_VIEW_SMALL_ICON
 271  
      * @see DiagramAppearance#STEREOTYPE_VIEW_BIG_ICON
 272  
      */
 273  1071
     private DiagramSettings.StereotypeStyle stereotypeStyle = 
 274  
         DiagramSettings.StereotypeStyle.TEXTUAL;   
 275  
     
 276  
     /**
 277  
      * The width of the profile icons when viewed at the small icon mode.
 278  
      * The icon width is resized to <code>ICON_WIDTH</code> and the height is 
 279  
      * set to a value that attempts to keep the original width/height 
 280  
      * proportion. 
 281  
      */
 282  
     private static final int ICON_WIDTH = 16;
 283  
     
 284  
     /**
 285  
      * When stereotypes are shown in <code>BigIcon</code> mode the 
 286  
      * <code>nameFig</code> is replaced by the one provided by the 
 287  
      * <code>FigProfileIcon</code> 
 288  
      * 
 289  
      * @see FigProfileIcon
 290  
      */
 291  
     private FigText originalNameFig;
 292  
     
 293  
     /**
 294  
      * EnclosedFigs are the Figs that are enclosed by this figure. Say that
 295  
      * it is a Package then these are the Classes, Interfaces, Packages etc
 296  
      * that are on this figure. This is not the same as the figures in the
 297  
      * FigGroup that this FigNodeModelElement "is", since these are the
 298  
      * figures that make up this high-level primitive figure.
 299  
      */
 300  1071
     private Vector<Fig> enclosedFigs = new Vector<Fig>();
 301  
 
 302  
     /**
 303  
      * The figure enclosing this figure such as a package surrounding a class.
 304  
      */
 305  
     private Fig encloser;
 306  
 
 307  
     // TODO: Bobs says - what is the purpose of this flag? Please document.
 308  1071
     private boolean readyToEdit = true;
 309  
     
 310  
     private boolean suppressCalcBounds;
 311  
     private static boolean showBoldName;
 312  
 
 313  
     private ItemUID itemUid;
 314  
 
 315  
     /**
 316  
      * Set the removeFromDiagram to false if this node may not
 317  
      * be removed from the diagram.
 318  
      */
 319  1071
     private boolean removeFromDiagram = true;
 320  
 
 321  
 
 322  
     /**
 323  
      * If the contains text to be edited by the user.
 324  
      */
 325  1071
     private boolean editable = true;
 326  
 
 327  
     // TODO: A more strongly typed data structure could be used here.
 328  1071
     private Set<Object[]> listeners = new HashSet<Object[]>();
 329  
 
 330  
     /**
 331  
      * Settings which affect rendering (color, font, line width, etc);
 332  
      */
 333  
     private DiagramSettings settings;
 334  
     
 335  
     /**
 336  
      * The notation settings for this specific fig.  We manage it separately
 337  
      * from DiagramSettings because it is more likely to change.
 338  
      */
 339  
     private NotationSettings notationSettings;
 340  
     
 341  
     /**
 342  
      * Construct an unplaced Fig with no owner using the given 
 343  
      * rendering settings.
 344  
      */
 345  
     private void constructFigs() {
 346  
         // TODO: Why isn't this stuff managed by the nameFig itself?
 347  1071
         nameFig.setFilled(true);
 348  1071
         nameFig.setText(placeString());
 349  1071
         nameFig.setBotMargin(7); // make space for the clarifier
 350  1071
         nameFig.setRightMargin(4); // margin between text and border
 351  1071
         nameFig.setLeftMargin(4);
 352  
 
 353  1071
         readyToEdit = false;
 354  
 
 355  1071
         setShadowSize(getSettings().getDefaultShadowWidth());
 356  
         /* TODO: how to handle changes in shadowsize 
 357  
          * from the project properties? */
 358  
         
 359  1071
         stereotypeStyle = getSettings().getDefaultStereotypeView();
 360  1071
     }
 361  
 
 362  
     /**
 363  
      * Construct a figure at a specific position for a given model element
 364  
      * with the given settings. This is the constructor used by the PGML
 365  
      * parser when loading a diagram from a file.<p>
 366  
      * 
 367  
      * Beware: the width and height in the given Rectangle are currently ignored.
 368  
      * According issue 5604 this is a bug.
 369  
      * 
 370  
      * @param element ModelElement associated with figure
 371  
      * @param bounds x & y are used to set position, width & height are ignored
 372  
      * @param renderSettings  the rendering settings to use for the Fig
 373  
      */
 374  
     protected FigNodeModelElement(Object element, Rectangle bounds, 
 375  
             DiagramSettings renderSettings) {
 376  1071
         super();
 377  1071
         super.setOwner(element);
 378  
         
 379  
         // TODO: We currently don't support per-fig settings for most stuff, so
 380  
         // we can just use the defaults that we were given.
 381  
 //        settings = new DiagramSettings(renderSettings);
 382  1071
         settings = renderSettings;
 383  
         
 384  
         // Be careful here since subclasses could have overridden this with
 385  
         // the assumption that it wouldn't be called before the constructors
 386  
         // finished
 387  1071
         super.setFillColor(FILL_COLOR);
 388  1071
         super.setLineColor(LINE_COLOR);
 389  1071
         super.setLineWidth(LINE_WIDTH);
 390  1071
         super.setTextColor(TEXT_COLOR); // Some subclasses will try to use this
 391  
         
 392  
         /*
 393  
          * Notation settings are different since, we know that, at a minimum,
 394  
          * the isShowPath() setting can change because with implement
 395  
          * PathContainer, so we make sure that we have a private copy of the
 396  
          * notation settings.
 397  
          */
 398  1071
         notationSettings = new NotationSettings(settings.getNotationSettings());
 399  
 
 400  
         // this rectangle marks the whole modelelement figure; everything
 401  
         // is inside it:
 402  1071
         bigPort = createBigPortFig();
 403  1071
         nameFig = new FigNameWithAbstractAndBold(element, 
 404  
                 new Rectangle(X0, Y0, WIDTH, NAME_FIG_HEIGHT), getSettings(), true);
 405  1071
         stereotypeFig = createStereotypeFig();
 406  1071
         constructFigs();
 407  
         
 408  
         // TODO: For a FigPool the element will be null.
 409  
         // When issue 5031 is resolved this constraint can be reinstated
 410  
 //        if (element == null) {
 411  
 //            throw new IllegalArgumentException("An owner must be supplied");
 412  
 //        }
 413  1071
         if (element != null && !Model.getFacade().isAUMLElement(element)) {
 414  0
             throw new IllegalArgumentException(
 415  
                     "The owner must be a model element - got a "
 416  
                     + element.getClass().getName());
 417  
         }
 418  
 
 419  1071
         nameFig.setText(placeString());
 420  
         
 421  1071
         if (element != null) {
 422  0
             NotationName nn = Notation.findNotation(notationSettings.getNotationLanguage());
 423  0
             notationProviderName =
 424  
                 NotationProviderFactory2.getInstance().getNotationProvider(
 425  
                         getNotationProviderType(), element, this, nn);
 426  
 
 427  
             /* This next line presumes that the 1st fig with this owner 
 428  
              * is the previous port - and consequently nullifies the owner 
 429  
              * of this 1st fig. */
 430  0
             bindPort(element, bigPort);
 431  
 
 432  
             // Add a listener for changes to any property
 433  0
             addElementListener(element);
 434  
         }
 435  
 
 436  1071
         if (bounds != null) {
 437  0
             setLocation(bounds.x, bounds.y);
 438  
         }
 439  
         
 440  
         // TODO: The following is carried over from setOwner, but probably 
 441  
         // isn't needed
 442  
 //        renderingChanged();
 443  
         // It does the following (add as needed):
 444  
 //        updateNameText();
 445  
 //        updateStereotypeText();
 446  
 //        updateStereotypeIcon();        
 447  
 //        updateBounds();
 448  
 //        damage();
 449  
         
 450  1071
         readyToEdit = true;
 451  1071
     }
 452  
 
 453  
     /**
 454  
      * Overrule this if a rectangle is not usable.
 455  
      * 
 456  
      * @return the Fig to be used as bigPort
 457  
      */
 458  
     protected Fig createBigPortFig() {
 459  1071
         return new FigRect(X0, Y0, 0, 0, DEBUG_COLOR, DEBUG_COLOR);
 460  
     }
 461  
     
 462  
     protected FigStereotypesGroup createStereotypeFig() {
 463  0
         return new FigStereotypesGroup(getOwner(), 
 464  
                 new Rectangle(X0, Y0, WIDTH, STEREOHEIGHT), settings);
 465  
     }
 466  
 
 467  
     
 468  
     
 469  
     /**
 470  
      * This is the final call at creation time of the Fig, i.e. here
 471  
      * it is put on a Diagram.
 472  
      * 
 473  
      * @param lay the Layer (which has a 1..1 relation to the Diagram)
 474  
      * @see org.tigris.gef.presentation.Fig#setLayer(org.tigris.gef.base.Layer)
 475  
      */
 476  
     @Override
 477  
     public void setLayer(Layer lay) {
 478  0
         super.setLayer(lay);
 479  0
         determineDefaultPathVisible();
 480  0
     }
 481  
 
 482  
 
 483  
     /**
 484  
      * Clone this figure. After the base clone method has been called determine
 485  
      * which child figs of the clone represent the name, stereotype and port.
 486  
      * <p>
 487  
      * TODO: enclosedFigs, encloser and eventSenders may also need to be cloned.
 488  
      * 
 489  
      * @see java.lang.Object#clone()
 490  
      * @return the cloned figure
 491  
      */
 492  
     @Override
 493  
     public Object clone() {
 494  0
         final FigNodeModelElement clone = (FigNodeModelElement) super.clone();
 495  
         
 496  0
         final Iterator cloneIter = clone.getFigs().iterator();
 497  0
         for (Object thisFig : getFigs()) {
 498  0
             final Fig cloneFig = (Fig) cloneIter.next();
 499  0
             if (thisFig == getBigPort()) {
 500  0
                 clone.setBigPort(cloneFig);
 501  
             }
 502  0
             if (thisFig == nameFig) {
 503  0
                 clone.nameFig = (FigSingleLineText) thisFig;
 504  
                 /* TODO: MVW: I think this has to be: 
 505  
                  * clone.nameFig = (FigSingleLineText) cloneFig;
 506  
                  * but have not the means to investigate, 
 507  
                  * since this code is not yet used.
 508  
                  * Enable the menu-items for Copy/Paste to test... 
 509  
                  * BTW: In some other FigNodeModelElement 
 510  
                  * classes I see the same mistake. */
 511  
             }
 512  0
             if (thisFig == getStereotypeFig()) {
 513  0
                 clone.stereotypeFig = (FigStereotypesGroup) thisFig;
 514  
                 /* Idem here:
 515  
                  * clone.stereotypeFig = (FigStereotypesGroup) cloneFig; */
 516  
             }
 517  0
         }
 518  0
         return clone;
 519  
     }
 520  
 
 521  
     /**
 522  
      * Default Reply text to be shown while placing node in diagram.
 523  
      * Overrule this when the text is not "new [UMLClassName]".
 524  
      *
 525  
      * @return the text to be shown while placing node in diagram
 526  
      */
 527  
     public String placeString() {
 528  2142
         if (Model.getFacade().isAModelElement(getOwner())) {
 529  0
             String placeString = Model.getFacade().getName(getOwner());
 530  0
             if (placeString == null) {
 531  0
                 placeString =
 532  
                     // TODO: I18N
 533  
                     "new " + Model.getFacade().getUMLClassName(getOwner());
 534  
             }
 535  0
             return placeString;
 536  
         }
 537  2142
         return "";
 538  
     }
 539  
 
 540  
     /**
 541  
      * @param id UID
 542  
      */
 543  
     public void setItemUID(ItemUID id) {
 544  0
         itemUid = id;
 545  0
     }
 546  
 
 547  
     /**
 548  
      * @return UID
 549  
      */
 550  
     public ItemUID getItemUID() {
 551  0
         return itemUid;
 552  
     }
 553  
 
 554  
     /**
 555  
      * Get the Fig that displays the model element name.
 556  
      *
 557  
      * @return the name Fig
 558  
      */
 559  
     protected FigText getNameFig() {
 560  2142
         return nameFig;
 561  
     }
 562  
     
 563  
     /**
 564  
      * Get the Rectangle in which the model elements name is displayed
 565  
      * @return bounding box for name
 566  
      */
 567  
     public Rectangle getNameBounds() {
 568  0
         return nameFig.getBounds();
 569  
     }
 570  
     
 571  
     /**
 572  
      * Set the Fig that displays the model element name.
 573  
      *
 574  
      * @param fig the name Fig
 575  
      */
 576  
     protected void setNameFig(FigText fig) {
 577  0
         nameFig = fig;
 578  0
         if (nameFig != null) {
 579  0
             updateFont();
 580  
         }
 581  0
     }
 582  
 
 583  
     /**
 584  
      * Get the name of the model element this Fig represents.
 585  
      *
 586  
      * @return the name of the model element
 587  
      */
 588  
     public String getName() {
 589  0
         return nameFig.getText();
 590  
     }
 591  
 
 592  
     /**
 593  
      * Change the name of the model element this Fig represents.
 594  
      *
 595  
      * @param n the name of the model element
 596  
      */
 597  
     public void setName(String n) {
 598  0
         nameFig.setText(n);
 599  0
     }
 600  
 
 601  
     /**
 602  
      * This method returns a Vector of one of these 4 types:
 603  
      * AbstractAction, JMenu, JMenuItem, JSeparator.
 604  
      * {@inheritDoc}
 605  
      */
 606  
     @Override
 607  
     public Vector getPopUpActions(MouseEvent me) {
 608  0
         ActionList popUpActions =
 609  
             new ActionList(super.getPopUpActions(me), isReadOnly());
 610  
 
 611  0
         final List<Action> modulesActions =
 612  
             ContextActionFactoryManager.getContextPopupActions();
 613  
         
 614  0
         for (Action a : modulesActions) {
 615  0
             if (a instanceof List) {
 616  0
                 JMenu m = new JMenu((Action) a);
 617  0
                 popUpActions.add(m);
 618  0
                 for (Action subAction : (List<Action>) a) {
 619  0
                     m.add(subAction);
 620  
                 }
 621  0
             } else {
 622  0
                 popUpActions.add(a);
 623  
             }
 624  
         }
 625  
         
 626  
         // Show ...
 627  0
         ArgoJMenu show = buildShowPopUp();
 628  0
         if (show.getMenuComponentCount() > 0) {
 629  0
             popUpActions.add(show);
 630  
         }
 631  
         
 632  
         // popupAddOffset should be equal to the number of items added here:
 633  0
         popUpActions.add(new JSeparator());
 634  0
         popupAddOffset = 1;
 635  0
         if (removeFromDiagram) {
 636  0
             popUpActions.add(
 637  
                     ProjectActions.getInstance().getRemoveFromDiagramAction());
 638  0
             popupAddOffset++;
 639  
         }
 640  
         
 641  0
         if (!isReadOnly()) {
 642  0
             popUpActions.add(new ActionDeleteModelElements());
 643  0
             popupAddOffset++;
 644  
         }
 645  
 
 646  
         /* Check if multiple items are selected: */
 647  0
         if (TargetManager.getInstance().getTargets().size() == 1) {
 648  
             
 649  
             // TODO: Having Critics actions here introduces an unnecessary
 650  
             // dependency on the Critics subsystem.  Have it register its
 651  
             // desired actions using an extension mechanism - tfm
 652  0
             ToDoList tdList = Designer.theDesigner().getToDoList();
 653  0
             List<ToDoItem> items = tdList.elementListForOffender(getOwner());
 654  0
             if (items != null && items.size() > 0) {
 655  
                 // TODO: This creates a dependency on the Critics subsystem.
 656  
                 // We need a generic way for modules (including our internal
 657  
                 // subsystems) to request addition of actions to the popup
 658  
                 // menu. - tfm 20080430
 659  0
                 ArgoJMenu critiques = new ArgoJMenu("menu.popup.critiques");
 660  0
                 ToDoItem itemUnderMouse = hitClarifier(me.getX(), me.getY());
 661  0
                 if (itemUnderMouse != null) {
 662  0
                     critiques.add(new ActionGoToCritique(itemUnderMouse));
 663  0
                     critiques.addSeparator();
 664  
                 }
 665  0
                 for (ToDoItem item : items) {
 666  0
                     if (item != itemUnderMouse) {
 667  0
                         critiques.add(new ActionGoToCritique(item));
 668  
                     }
 669  
                 }
 670  0
                 popUpActions.add(0, new JSeparator());
 671  0
                 popUpActions.add(0, critiques);
 672  
             }
 673  
         }
 674  
 
 675  
         // Add stereotypes submenu
 676  0
         Collection<Object> elements = new ArrayList<Object>();
 677  0
         Object owner = getOwner();
 678  0
         if (owner != null) {
 679  0
             elements.add(owner);
 680  
         }
 681  0
         for (Object o : TargetManager.getInstance().getTargets()) {
 682  0
             Object element = null;
 683  0
             if (Model.getFacade().isAUMLElement(o)) {
 684  0
                 element = o;
 685  0
             } else if (o instanceof Fig) {
 686  0
                 element = ((Fig) o).getOwner();
 687  
             }
 688  0
             if (element != null && element != owner) {
 689  0
                 elements.add(element);
 690  
             }
 691  0
         }
 692  0
         final Action[] stereoActions =
 693  
             StereotypeUtility.getApplyStereotypeActions(elements);
 694  0
         if (stereoActions != null) {
 695  0
             popUpActions.add(0, new JSeparator());
 696  0
             final ArgoJMenu stereotypes =
 697  
                 new ArgoJMenu("menu.popup.apply-stereotypes");
 698  0
             for (Action action : stereoActions) {
 699  0
                 stereotypes.addCheckItem(action);
 700  
             }
 701  0
             popUpActions.add(0, stereotypes);
 702  
         }
 703  
             
 704  0
         if (TargetManager.getInstance().getTargets().size() == 1) {
 705  
             // add stereotype view submenu
 706  0
             ArgoJMenu stereotypesView =
 707  
                 new ArgoJMenu("menu.popup.stereotype-view");
 708  
             
 709  
             // TODO: There are cyclic dependencies between ActionStereotypeView*
 710  
             // and FigNodeModelElement.  Register these actions opaquely since
 711  
             // we don't what they are. - tfm
 712  0
             stereotypesView.addRadioItem(new ActionStereotypeViewTextual(this));
 713  0
             stereotypesView.addRadioItem(new ActionStereotypeViewBigIcon(this));
 714  0
             stereotypesView.addRadioItem(
 715  
                     new ActionStereotypeViewSmallIcon(this));
 716  
             
 717  0
             popUpActions.add(0, stereotypesView);
 718  
         }
 719  
 
 720  0
         return popUpActions;
 721  
     }
 722  
 
 723  
     protected ArgoJMenu buildShowPopUp() {
 724  0
         ArgoJMenu showMenu = new ArgoJMenu("menu.popup.show");
 725  
 
 726  0
         for (UndoableAction ua : ActionSetPath.getActions()) {
 727  0
             showMenu.add(ua);
 728  
         }
 729  0
         return showMenu;
 730  
     }
 731  
 
 732  
     /**
 733  
      * @return the pop-up menu item for Visibility
 734  
      */
 735  
     protected Object buildVisibilityPopUp() {
 736  0
         ArgoJMenu visibilityMenu = new ArgoJMenu("menu.popup.visibility");
 737  
 
 738  0
         visibilityMenu.addRadioItem(new ActionVisibilityPublic(getOwner()));
 739  0
         visibilityMenu.addRadioItem(new ActionVisibilityPrivate(getOwner()));
 740  0
         visibilityMenu.addRadioItem(new ActionVisibilityProtected(getOwner()));
 741  0
         visibilityMenu.addRadioItem(new ActionVisibilityPackage(getOwner()));
 742  
         
 743  0
         return visibilityMenu;
 744  
     }
 745  
 
 746  
     /**
 747  
      * Build a pop-up menu item for the various modifiers.<p>
 748  
      *
 749  
      * This function is designed to be easily extendable with new items.
 750  
      *
 751  
      * @param items bitwise OR of the items: ROOT, ABSTRACT, LEAF, ACTIVE.
 752  
      * @return the menu item
 753  
      */
 754  
     protected Object buildModifierPopUp(int items) {
 755  0
         ArgoJMenu modifierMenu = new ArgoJMenu("menu.popup.modifiers");
 756  
 
 757  0
         if ((items & ABSTRACT) > 0) {
 758  0
             modifierMenu.addCheckItem(new ActionModifierAbstract(getOwner()));
 759  
         }
 760  0
         if ((items & LEAF) > 0) {
 761  0
             modifierMenu.addCheckItem(new ActionModifierLeaf(getOwner()));
 762  
         }
 763  0
         if ((items & ROOT) > 0) {
 764  0
             modifierMenu.addCheckItem(new ActionModifierRoot(getOwner()));
 765  
         }
 766  0
         if ((items & ACTIVE) > 0) {
 767  0
             modifierMenu.addCheckItem(new ActionModifierActive(getOwner()));
 768  
         }
 769  
 
 770  0
         return modifierMenu;
 771  
     }
 772  
 
 773  
     /*
 774  
      * @see org.tigris.gef.presentation.Fig#getEnclosingFig()
 775  
      */
 776  
     @Override
 777  
     public Fig getEnclosingFig() {
 778  0
         return encloser;
 779  
     }
 780  
 
 781  
     /*
 782  
      * Updates the modelelement container if the fig is moved in or
 783  
      * out another fig. If this fig doesn't have an enclosing fig
 784  
      * anymore, the namespace of the diagram will be the owning
 785  
      * modelelement. If this fig is moved inside another
 786  
      * FigNodeModelElement the owner of that fignodemodelelement will
 787  
      * be the owning modelelement.
 788  
      * 
 789  
      * @see org.tigris.gef.presentation.FigNode#setEnclosingFig(org.tigris.gef.presentation.Fig)
 790  
      */
 791  
     @Override
 792  
     public void setEnclosingFig(Fig newEncloser) {
 793  0
         Fig oldEncloser = encloser;
 794  
         
 795  0
         LayerPerspective layer = (LayerPerspective) getLayer();
 796  0
         if (layer != null) {
 797  0
             ArgoDiagram diagram = (ArgoDiagram) layer.getDiagram();
 798  0
             diagram.encloserChanged(
 799  
                     this,
 800  
                     (FigNode) oldEncloser,
 801  
                     (FigNode) newEncloser);
 802  
         }
 803  
         
 804  0
         super.setEnclosingFig(newEncloser);
 805  
         
 806  0
         if (layer != null && newEncloser != oldEncloser) {
 807  0
             Diagram diagram = layer.getDiagram();
 808  0
             if (diagram instanceof ArgoDiagram) {
 809  0
                 ArgoDiagram umlDiagram = (ArgoDiagram) diagram;
 810  
                 // Set the namespace of the enclosed model element to the
 811  
                 // namespace of the encloser.
 812  0
                 Object namespace = null;
 813  0
                 if (newEncloser == null) {
 814  
                     // The node's been placed on the diagram
 815  0
                     umlDiagram.setModelElementNamespace(getOwner(), null);
 816  
                 } else { 
 817  
                     // The node's been placed within some Fig
 818  0
                     namespace = newEncloser.getOwner();
 819  0
                     if (Model.getFacade().isANamespace(namespace)) {
 820  0
                         umlDiagram.setModelElementNamespace(
 821  
                                 getOwner(), namespace);
 822  
                     }
 823  
                 }
 824  
             }
 825  
 
 826  0
             if (encloser instanceof FigNodeModelElement) {
 827  0
                 ((FigNodeModelElement) encloser).removeEnclosedFig(this);
 828  
             }
 829  0
             if (newEncloser instanceof FigNodeModelElement) {
 830  0
                 ((FigNodeModelElement) newEncloser).addEnclosedFig(this);
 831  
             }
 832  
         }
 833  0
         encloser = newEncloser;
 834  0
     }
 835  
 
 836  
     /**
 837  
      * Handle the case where this fig is moved into a Component.
 838  
      * 
 839  
      * @param newEncloser the new encloser for this Fig
 840  
      */
 841  
     protected void moveIntoComponent(Fig newEncloser) {
 842  0
         final Object component = newEncloser.getOwner();
 843  0
         final Object owner = getOwner();
 844  
 
 845  0
         assert Model.getFacade().isAComponent(component);
 846  0
         assert Model.getFacade().isAUMLElement(owner);
 847  
 
 848  0
         final Collection er1 = Model.getFacade().getElementResidences(owner);
 849  0
         final Collection er2 = Model.getFacade().getResidentElements(component);
 850  0
         boolean found = false;
 851  
         // Find all ElementResidences between the class and the component:
 852  0
         final Collection<Object> common = new ArrayList<Object>(er1);
 853  0
         common.retainAll(er2);
 854  0
         for (Object elementResidence : common) {
 855  0
             if (!found) {
 856  0
                 found = true;
 857  
                 // There is already a correct ElementResidence
 858  
             } else {
 859  
                 // There were 2 ElementResidences .. strange case.
 860  0
                 Model.getUmlFactory().delete(elementResidence);
 861  
             }
 862  
         }
 863  0
         if (!found) {
 864  
             // There was no ElementResidence yet, so let's create one:
 865  0
             Model.getCoreFactory().buildElementResidence(
 866  
                     owner, component);
 867  
         }
 868  0
     }
 869  
 
 870  
     /**
 871  
      * Add a Fig that is enclosed by this figure.
 872  
      * 
 873  
      * @param fig The fig to be added
 874  
      */
 875  
     public void addEnclosedFig(Fig fig) {
 876  0
         enclosedFigs.add(fig);
 877  0
     }
 878  
 
 879  
     /**
 880  
      * Removes the given Fig from the list of enclosed Figs.
 881  
      * 
 882  
      * @param fig The Fig to be removed
 883  
      */
 884  
     public void removeEnclosedFig(Fig fig) {
 885  0
         enclosedFigs.remove(fig);
 886  0
     }
 887  
 
 888  
     /*
 889  
      * @see org.tigris.gef.presentation.Fig#getEnclosedFigs()
 890  
      */
 891  
     @Override
 892  
     public Vector<Fig> getEnclosedFigs() {
 893  0
         return enclosedFigs;
 894  
     }
 895  
 
 896  
 
 897  
     /*
 898  
      * @see org.tigris.gef.presentation.Fig#makeSelection()
 899  
      */
 900  
     @Override
 901  
     public Selection makeSelection() {
 902  0
         return new SelectionDefaultClarifiers(this);
 903  
     }
 904  
 
 905  
     /**
 906  
      * Displays visual indications of pending ToDoItems.
 907  
      * Please note that the list of advices (ToDoList) is not the same
 908  
      * as the list of element known by the FigNode (_figs). Therefore,
 909  
      * it is necessary to check if the graphic item exists before drawing
 910  
      * on it. See ClAttributeCompartment for an example.
 911  
      * @param g the graphics device
 912  
      * @see org.argouml.uml.cognitive.critics.ClAttributeCompartment
 913  
      */
 914  
     public void paintClarifiers(Graphics g) {
 915  
         // TODO: Generalize extension and remove critic specific stuff
 916  0
         int iconX = getX();
 917  0
         int iconY = getY() - 10;
 918  0
         ToDoList tdList = Designer.theDesigner().getToDoList();
 919  0
         List<ToDoItem> items = tdList.elementListForOffender(getOwner());
 920  0
         for (ToDoItem item : items) {
 921  0
             Icon icon = item.getClarifier();
 922  0
             if (icon instanceof Clarifier) {
 923  0
                 ((Clarifier) icon).setFig(this);
 924  0
                 ((Clarifier) icon).setToDoItem(item);
 925  
             }
 926  0
             if (icon != null) {
 927  0
                 icon.paintIcon(null, g, iconX, iconY);
 928  0
                 iconX += icon.getIconWidth();
 929  
             }
 930  0
         }
 931  0
         items = tdList.elementListForOffender(this);
 932  0
         for (ToDoItem item : items) {
 933  0
             Icon icon = item.getClarifier();
 934  0
             if (icon instanceof Clarifier) {
 935  0
                 ((Clarifier) icon).setFig(this);
 936  0
                 ((Clarifier) icon).setToDoItem(item);
 937  
             }
 938  0
             if (icon != null) {
 939  0
                 icon.paintIcon(null, g, iconX, iconY);
 940  0
                 iconX += icon.getIconWidth();
 941  
             }
 942  0
         }
 943  0
     }
 944  
 
 945  
     /**
 946  
      * @param x the x of the hit
 947  
      * @param y the y of the hit
 948  
      * @return the todo item of which the clarifier has been hit
 949  
      */
 950  
     protected ToDoItem hitClarifier(int x, int y) {
 951  
         // TODO: ToDoItem stuff should be made an opaque extension
 952  0
         int iconX = getX();
 953  0
         ToDoList tdList = Designer.theDesigner().getToDoList();
 954  0
         List<ToDoItem> items = tdList.elementListForOffender(getOwner());
 955  0
         for (ToDoItem item : items) {
 956  0
             Icon icon = item.getClarifier();
 957  0
             int width = icon.getIconWidth();
 958  0
             if (y >= getY() - 15
 959  
                     && y <= getY() + 10
 960  
                     && x >= iconX
 961  
                     && x <= iconX + width) {
 962  0
                 return item;
 963  
             }
 964  0
             iconX += width;
 965  0
         }
 966  0
         for (ToDoItem item : items) {
 967  0
             Icon icon = item.getClarifier();
 968  0
             if (icon instanceof Clarifier) {
 969  0
                 ((Clarifier) icon).setFig(this);
 970  0
                 ((Clarifier) icon).setToDoItem(item);
 971  0
                 if (((Clarifier) icon).hit(x, y)) {
 972  0
                     return item;
 973  
                 }
 974  
             }
 975  0
         }
 976  0
         items = tdList.elementListForOffender(this);
 977  0
         for (ToDoItem item : items) {
 978  0
             Icon icon = item.getClarifier();
 979  0
             int width = icon.getIconWidth();
 980  0
             if (y >= getY() - 15
 981  
                     && y <= getY() + 10
 982  
                     && x >= iconX
 983  
                     && x <= iconX + width) {
 984  0
                 return item;
 985  
             }
 986  0
             iconX += width;
 987  0
         }
 988  0
         for (ToDoItem item : items) {
 989  0
             Icon icon = item.getClarifier();
 990  0
             if (icon instanceof Clarifier) {
 991  0
                 ((Clarifier) icon).setFig(this);
 992  0
                 ((Clarifier) icon).setToDoItem(item);
 993  0
                 if (((Clarifier) icon).hit(x, y)) {
 994  0
                     return item;
 995  
                 }
 996  
             }
 997  0
         }
 998  0
         return null;
 999  
     }
 1000  
 
 1001  
     /*
 1002  
      * @see org.tigris.gef.presentation.Fig#getTipString(java.awt.event.MouseEvent)
 1003  
      */
 1004  
     @Override
 1005  
     public String getTipString(MouseEvent me) {
 1006  
         // TODO: Generalize extension and remove critic specific code
 1007  0
         ToDoItem item = hitClarifier(me.getX(), me.getY());
 1008  0
         String tip = "";
 1009  0
         if (item != null
 1010  
             && Globals.curEditor().getSelectionManager().containsFig(this)) {
 1011  0
             tip = item.getHeadline() + " ";
 1012  0
         } else if (getOwner() != null) {
 1013  0
             tip = Model.getFacade().getTipString(getOwner());
 1014  
         } else {
 1015  0
             tip = toString();
 1016  
         }
 1017  0
         if (tip != null && tip.length() > 0 && !tip.endsWith(" ")) {
 1018  0
             tip += " ";
 1019  
         }
 1020  0
         return tip;
 1021  
     }
 1022  
 
 1023  
     ////////////////////////////////////////////////////////////////
 1024  
     // event handlers
 1025  
 
 1026  
     /*
 1027  
      * @see java.beans.VetoableChangeListener#vetoableChange(java.beans.PropertyChangeEvent)
 1028  
      */
 1029  
     public void vetoableChange(PropertyChangeEvent pce) {
 1030  0
         LOG.debug("in vetoableChange");
 1031  0
         Object src = pce.getSource();
 1032  0
         if (src == getOwner()) {
 1033  0
             DelayedChangeNotify delayedNotify =
 1034  
                 new DelayedChangeNotify(this, pce);
 1035  0
             SwingUtilities.invokeLater(delayedNotify);
 1036  0
         } else {
 1037  0
             LOG.debug("FigNodeModelElement got vetoableChange"
 1038  
                       + " from non-owner:"
 1039  
                       + src);
 1040  
         }
 1041  0
     }
 1042  
 
 1043  
     /*
 1044  
      * @see org.argouml.kernel.DelayedVChangeListener#delayedVetoableChange(java.beans.PropertyChangeEvent)
 1045  
      */
 1046  
     public void delayedVetoableChange(PropertyChangeEvent pce) {
 1047  0
         LOG.debug("in delayedVetoableChange");
 1048  
         // update any text, colors, fonts, etc.
 1049  0
         renderingChanged();
 1050  0
         endTrans();
 1051  0
     }
 1052  
 
 1053  
     /**
 1054  
      * Determine new bounds. <p>
 1055  
      * 
 1056  
      * This algorithm makes the box grow 
 1057  
      * (if the calculated minimum size grows), 
 1058  
      * but then it can never shrink again 
 1059  
      * (not even if the calculated minimum size is smaller).<p>
 1060  
      * 
 1061  
      * If the user can not resize the fig, e.g. like the FigActor or FigFinalState, 
 1062  
      * then we return the original size.
 1063  
      */
 1064  
     protected void updateBounds() {
 1065  0
         if (!checkSize) {
 1066  0
             return;
 1067  
         }
 1068  0
         Rectangle bbox = getBounds();
 1069  0
         Dimension minSize = getMinimumSize();
 1070  0
         if (isResizable()) {
 1071  0
             bbox.width = Math.max(bbox.width, minSize.width);
 1072  0
             bbox.height = Math.max(bbox.height, minSize.height);
 1073  
         }
 1074  
         /* Only update the bounds if they change:  */
 1075  0
         if (bbox.x != getX()
 1076  
                 || bbox.y != getY()
 1077  
                 || bbox.width != getWidth()
 1078  
                 || bbox.height != getHeight()) {
 1079  0
             setBounds(bbox.x, bbox.y, bbox.width, bbox.height);
 1080  
         }
 1081  0
     }
 1082  
 
 1083  
     /*
 1084  
      * @see java.beans.PropertyChangeListener#propertyChange(java.beans.PropertyChangeEvent)
 1085  
      */
 1086  
     public void propertyChange(final PropertyChangeEvent pve) {
 1087  32
         final Object src = pve.getSource();
 1088  32
         final String pName = pve.getPropertyName();
 1089  32
         if (pve instanceof DeleteInstanceEvent && src == getOwner()) {
 1090  0
             removeFromDiagram();
 1091  0
             return;
 1092  
         }
 1093  
         
 1094  
         // We are getting events we don't want. Filter them out.
 1095  32
         if (pve.getPropertyName().equals("supplierDependency")
 1096  
                 && Model.getFacade().isADependency(pve.getOldValue())) {
 1097  
             // TODO: Can we instruct the model event pump not to send these in
 1098  
             // the first place? See defect 5095.
 1099  0
             return;
 1100  
         }
 1101  
         
 1102  
         // We handle and consume editing events
 1103  32
         if (pName.equals("editing")
 1104  
                 && Boolean.FALSE.equals(pve.getNewValue())) {
 1105  
             try {
 1106  
                 //parse the text that was edited
 1107  0
                 textEdited((FigText) src);
 1108  
                 // resize the FigNode to accommodate the new text
 1109  0
                 final Rectangle bbox = getBounds();
 1110  0
                 final Dimension minSize = getMinimumSize();
 1111  0
                 bbox.width = Math.max(bbox.width, minSize.width);
 1112  0
                 bbox.height = Math.max(bbox.height, minSize.height);
 1113  0
                 setBounds(bbox.x, bbox.y, bbox.width, bbox.height);
 1114  0
                 endTrans();
 1115  0
             } catch (PropertyVetoException ex) {
 1116  0
                 LOG.error("could not parse the text entered. "
 1117  
                         + "PropertyVetoException",
 1118  
                         ex);
 1119  0
             }
 1120  32
         } else if (pName.equals("editing")
 1121  
                 && Boolean.TRUE.equals(pve.getNewValue())) {
 1122  0
             if (!isReadOnly()) {
 1123  0
                 textEditStarted((FigText) src);
 1124  
             }
 1125  
         } else {
 1126  32
             super.propertyChange(pve);
 1127  
         }
 1128  32
         if (Model.getFacade().isAUMLElement(src)) {
 1129  0
             final UmlChangeEvent event = (UmlChangeEvent) pve;
 1130  
             /* If the source of the event is an UML object,
 1131  
              * e.g. the owner of this Fig (but not always only the owner
 1132  
              * is shown, e.g. for a class, also its attributes are shown),
 1133  
              * then the UML model has been changed.
 1134  
              */
 1135  0
             final Object owner = getOwner();
 1136  0
             if (owner == null) {
 1137  
                 // TODO: Should this not be an assert?
 1138  0
                 return;
 1139  
             }
 1140  
             
 1141  
             try {
 1142  0
                 modelChanged(event);
 1143  0
             } catch (InvalidElementException e) {
 1144  0
                 if (LOG.isDebugEnabled()) {
 1145  0
                     LOG.debug("modelChanged method accessed deleted element"
 1146  
                             + formatEvent(event),
 1147  
                             e);
 1148  
                 }
 1149  0
             }
 1150  
             
 1151  0
             if (event.getSource() == owner 
 1152  
                     && "stereotype".equals(event.getPropertyName())) {
 1153  0
                 stereotypeChanged(event);            
 1154  
             }
 1155  
 
 1156  0
             Runnable doWorkRunnable = new Runnable() {
 1157  
                 public void run() {
 1158  
                     try {
 1159  0
                         updateLayout(event);
 1160  0
                     } catch (InvalidElementException e) {
 1161  0
                         if (LOG.isDebugEnabled()) {
 1162  0
                             LOG.debug("updateLayout method accessed "
 1163  
                                     + "deleted element " 
 1164  
                                     + formatEvent(event), e);
 1165  
                         }
 1166  0
                     }
 1167  0
                 }  
 1168  
             };
 1169  0
             SwingUtilities.invokeLater(doWorkRunnable);
 1170  
         }
 1171  32
     }
 1172  
     
 1173  
     private String formatEvent(PropertyChangeEvent event) {
 1174  0
         return "\n\t event = " + event.getClass().getName() 
 1175  
                 + "\n\t source = " + event.getSource() 
 1176  
                 + "\n\t old = " + event.getOldValue()
 1177  
                 + "\n\t name = " + event.getPropertyName();
 1178  
     }
 1179  
     
 1180  
     /**
 1181  
      * Return true if the model element that this Fig represents is read only
 1182  
      * @return The model element is read only.
 1183  
      */
 1184  
     private boolean isReadOnly() {
 1185  
         try {
 1186  0
             return Model.getModelManagementHelper().isReadOnly(getOwner());
 1187  0
         } catch (InvalidElementException e) {
 1188  0
             return true;
 1189  
         }
 1190  
     }
 1191  
 
 1192  
     /**
 1193  
      * Called by propertyChanged when it detects that a stereotype
 1194  
      * has been added or removed. On removal the FigNode removes its
 1195  
      * listener to that stereotype. When a new stereotype is detected
 1196  
      * we add a listener.
 1197  
      * TODO: Bob says: In my opinion we shouldn't be doing this here.
 1198  
      * FigStereotype should always be listening to change of its
 1199  
      * owners name.
 1200  
      * FigStereotypesCompartment should always be listening for add
 1201  
      * or remove of Stereotypes to its owner.
 1202  
      * Those classes will need to pass some event to the FigNode on
 1203  
      * the AWT thread only if a change results in a change of size
 1204  
      * that requires a redraw.
 1205  
      * <p>NOTE: Runs at the Model (MDR) Thread </p>
 1206  
      * @param event the UmlChangeEvent that caused the change
 1207  
      */
 1208  
     private void stereotypeChanged(final UmlChangeEvent event) {
 1209  0
         final Object owner = getOwner();
 1210  0
         assert owner != null;
 1211  
         try {          
 1212  0
             if (event.getOldValue() != null) {
 1213  0
                 removeElementListener(event.getOldValue());
 1214  
             }
 1215  0
             if (event.getNewValue() != null) {
 1216  0
                 addElementListener(event.getNewValue(), "name");
 1217  
             }
 1218  0
         } catch (InvalidElementException e) {
 1219  0
             LOG.debug("stereotypeChanged method accessed deleted element ", e);
 1220  0
         }
 1221  0
     }
 1222  
 
 1223  
     /**
 1224  
      * This method is called when the user doubleclicked on the text field,
 1225  
      * and starts editing. Subclasses should overrule this field to e.g.
 1226  
      * supply help to the user about the used format. <p>
 1227  
      *
 1228  
      * It is also possible to alter the text to be edited
 1229  
      * already here, e.g. by adding the stereotype in front of the name,
 1230  
      * by using setFullyHandleStereotypes(true) in the NotationSettings 
 1231  
      * argument of the NotationProvider.toString() function, 
 1232  
      * but that seems not user-friendly. See issue 3838.
 1233  
      *
 1234  
      * @param ft the FigText that will be edited and contains the start-text
 1235  
      */
 1236  
     protected void textEditStarted(FigText ft) {
 1237  0
         if (ft == getNameFig()) {
 1238  0
             showHelp(notationProviderName.getParsingHelp());
 1239  0
             ft.setText(notationProviderName.toString(getOwner(), 
 1240  
                     getNotationSettings()));
 1241  
         }
 1242  0
         if (ft instanceof CompartmentFigText) {
 1243  0
             final CompartmentFigText figText = (CompartmentFigText) ft;
 1244  0
             showHelp(figText.getNotationProvider().getParsingHelp());
 1245  0
             figText.setText(figText.getNotationProvider().toString(
 1246  
                     figText.getOwner(), getNotationSettings()));
 1247  
         }
 1248  0
     }
 1249  
 
 1250  
     /**
 1251  
      * Utility function to localize the given string with help text, and show it
 1252  
      * in the status bar of the ArgoUML window. This function is used in favour
 1253  
      * of the inline call to enable later improvements; e.g. it would be
 1254  
      * possible to show a help-balloon.
 1255  
      * <p>
 1256  
      * TODO: Work this out. One matter to possibly improve: show multiple lines.
 1257  
      * 
 1258  
      * @param s the given string to be localized and shown
 1259  
      */
 1260  
     protected void showHelp(String s) {
 1261  0
         if (s == null) {
 1262  
             // Convert null to empty string and clear help message
 1263  0
             ArgoEventPump.fireEvent(new ArgoHelpEvent(
 1264  
                     ArgoEventTypes.HELP_CHANGED, this, ""));
 1265  
         } else {
 1266  0
             ArgoEventPump.fireEvent(new ArgoHelpEvent(
 1267  
                     ArgoEventTypes.HELP_CHANGED, this, Translator.localize(s)));
 1268  
         }
 1269  0
     }
 1270  
 
 1271  
     /**
 1272  
      * This method is called after the user finishes editing a text
 1273  
      * field that is in the FigNodeModelElement.  Determine which
 1274  
      * field and update the model.  This class handles the name,
 1275  
      * the stereotype, and any CompartmentFigTexts.
 1276  
      * Subclasses should override to handle other text elements.
 1277  
      *
 1278  
      * @param ft the FigText that has been edited and contains the new text
 1279  
      * @throws PropertyVetoException thrown when new text represents
 1280  
      * an unacceptable value
 1281  
      */
 1282  
     protected void textEdited(FigText ft) throws PropertyVetoException {
 1283  0
         if (ft == nameFig) {
 1284  
             // TODO: Can we delegate this to a specialist FigName class?
 1285  0
             if (getOwner() == null) {
 1286  0
                 return;
 1287  
             }
 1288  0
             notationProviderName.parse(getOwner(), ft.getText());
 1289  0
             ft.setText(notationProviderName.toString(getOwner(), 
 1290  
                     getNotationSettings()));
 1291  
         }
 1292  0
         if (ft instanceof CompartmentFigText) {
 1293  0
             final CompartmentFigText figText = (CompartmentFigText) ft;
 1294  0
             figText.getNotationProvider().parse(ft.getOwner(), ft.getText());
 1295  0
             ft.setText(figText.getNotationProvider().toString(
 1296  
                     ft.getOwner(), getNotationSettings()));
 1297  
         }
 1298  0
     }
 1299  
 
 1300  
     ////////////////////////////////////////////////////////////////
 1301  
     // event handlers - MouseListener implementation
 1302  
 
 1303  
     /*
 1304  
      * If the user double clicks on any part of this FigNode, pass it
 1305  
      * down to one of the internal Figs. This allows the user to
 1306  
      * initiate direct text editing.
 1307  
      *
 1308  
      * @see java.awt.event.MouseListener#mouseClicked(java.awt.event.MouseEvent)
 1309  
      */
 1310  
     @Override
 1311  
     public void mouseClicked(MouseEvent me) {
 1312  0
         if (!readyToEdit) {
 1313  0
             if (Model.getFacade().isAModelElement(getOwner())) {
 1314  
                 // TODO: Why is this clearing the name?!?! - tfm
 1315  0
                 Model.getCoreHelper().setName(getOwner(), "");
 1316  0
                 readyToEdit = true;
 1317  
             } else {
 1318  0
                 LOG.debug("not ready to edit name");
 1319  0
                 return;
 1320  
             }
 1321  
         }
 1322  0
         if (me.isConsumed()) {
 1323  0
             return;
 1324  
         }
 1325  0
         if (me.getClickCount() >= 2
 1326  
                 && !(me.isPopupTrigger()
 1327  
                         || me.getModifiers() == InputEvent.BUTTON3_MASK)
 1328  
                 && getOwner() != null
 1329  
                 && !isReadOnly()) {
 1330  0
             Rectangle r = new Rectangle(me.getX() - 2, me.getY() - 2, 4, 4);
 1331  0
             Fig f = hitFig(r);
 1332  0
             if (f instanceof MouseListener && f.isVisible()) {
 1333  0
                 ((MouseListener) f).mouseClicked(me);
 1334  0
             } else if (f instanceof FigGroup && f.isVisible()) {
 1335  
                 //this enables direct text editing for sub figs of a
 1336  
                 //FigGroup object:
 1337  0
                 Fig f2 = ((FigGroup) f).hitFig(r);
 1338  0
                 if (f2 instanceof MouseListener) {
 1339  0
                     ((MouseListener) f2).mouseClicked(me);
 1340  
                 } else {
 1341  0
                     createContainedModelElement((FigGroup) f, me);
 1342  
                 }
 1343  
             }
 1344  
         }
 1345  0
     }
 1346  
 
 1347  
     /*
 1348  
      * @see java.awt.event.KeyListener#keyPressed(java.awt.event.KeyEvent)
 1349  
      */
 1350  
     public void keyPressed(KeyEvent ke) {
 1351  0
         if (ke.isConsumed() || getOwner() == null) {
 1352  0
             return;
 1353  
         }
 1354  0
         nameFig.keyPressed(ke);
 1355  0
     }
 1356  
 
 1357  
     /*
 1358  
      * @see java.awt.event.KeyListener#keyReleased(java.awt.event.KeyEvent)
 1359  
      */
 1360  
     public void keyReleased(KeyEvent ke) {
 1361  0
         if (ke.isConsumed() || getOwner() == null) {
 1362  0
             return;
 1363  
         }
 1364  0
         nameFig.keyReleased(ke);
 1365  0
     }
 1366  
 
 1367  
     /*
 1368  
      * @see java.awt.event.KeyListener#keyTyped(java.awt.event.KeyEvent)
 1369  
      */
 1370  
     public void keyTyped(KeyEvent ke) {
 1371  0
         if (!editable || isReadOnly()) {
 1372  0
             return;
 1373  
         }
 1374  0
         if (!readyToEdit) {
 1375  0
             if (Model.getFacade().isAModelElement(getOwner())) {
 1376  0
                 Model.getCoreHelper().setName(getOwner(), "");
 1377  0
                 readyToEdit = true;
 1378  
             } else {
 1379  0
                 LOG.debug("not ready to edit name");
 1380  0
                 return;
 1381  
             }
 1382  
         }
 1383  0
         if (ke.isConsumed() || getOwner() == null) {
 1384  0
             return;
 1385  
         }
 1386  0
         nameFig.keyTyped(ke);
 1387  0
     }
 1388  
 
 1389  
     /**
 1390  
      * This is a template method called by the ArgoUML framework as the result
 1391  
      * of a change to a model element. Do not call this method directly
 1392  
      * yourself.
 1393  
      * <p>Override this in any subclasses in order to change what model
 1394  
      * elements the FigNode is listening to as a result of change to the model.
 1395  
      * </p>
 1396  
      * <p>This method is guaranteed by the framework to be running on the same
 1397  
      * thread as the model subsystem.</p>
 1398  
      * TODO: Lets refactor this at some time to take UmlChangeEvent argument
 1399  
      *
 1400  
      * @param event the UmlChangeEvent that caused the change
 1401  
      */
 1402  
     protected void modelChanged(PropertyChangeEvent event) {
 1403  0
         if (event instanceof AssociationChangeEvent 
 1404  
                 || event instanceof AttributeChangeEvent) {
 1405  
             // TODO: This brute force approach of updating listeners on each
 1406  
             // and every event, without checking the event type or any other
 1407  
             // information is going to cause lots of InvalidElementExceptions
 1408  
             // in subclasses implementations of updateListeners (and they 
 1409  
             // won't have the event information to make their own decisions)
 1410  0
             updateListeners(getOwner(), getOwner());
 1411  
         }
 1412  0
     }    
 1413  
     
 1414  
     ////////////////////////////////////////////////////////////////
 1415  
     // internal methods
 1416  
     
 1417  
     /**
 1418  
      * This is a template method called by the ArgoUML framework as the result
 1419  
      * of a change to a model element. Do not call this method directly
 1420  
      * yourself.
 1421  
      * <p>Override this in any subclasses in order to restructure the FigNode
 1422  
      * due to change of any model element that this FigNode is listening to.</p>
 1423  
      * <p>This method automatically updates the stereotype rendering.</p>
 1424  
      * <p>The default behavior is to update the name and stereotype text.</p>
 1425  
      * <p>For e.g. a Package, if the visibility is changed 
 1426  
      * via the properties panel, then
 1427  
      * the display of it on the diagram has to follow the change.
 1428  
      * This is not handled here, but by the notationProviderName.</p>
 1429  
      * <p>This method is guaranteed by the framework to be running on the 
 1430  
      * Swing/AWT thread.</p>
 1431  
      *
 1432  
      * @param event the UmlChangeEvent that caused the change
 1433  
      */
 1434  
     protected void updateLayout(UmlChangeEvent event) {
 1435  0
         assert event != null;
 1436  0
         final Object owner = getOwner();
 1437  0
         assert owner != null;
 1438  0
         if (owner == null) {
 1439  0
             return;
 1440  
         }
 1441  0
         boolean needDamage = false;
 1442  0
         if (event instanceof AssociationChangeEvent 
 1443  
                 || event instanceof AttributeChangeEvent) {
 1444  0
             if (notationProviderName != null) {
 1445  0
                 updateNameText();
 1446  
             }
 1447  0
             needDamage = true;
 1448  
         }
 1449  0
         if (event.getSource() == owner
 1450  
                 && "stereotype".equals(event.getPropertyName())) {
 1451  0
             updateStereotypeText();
 1452  0
             updateStereotypeIcon();
 1453  0
             needDamage = true;
 1454  
         }
 1455  0
         if (needDamage) {
 1456  0
             damage();
 1457  
         }
 1458  0
     }
 1459  
 
 1460  
     /**
 1461  
      * Create a new model element contained in the fig owner.
 1462  
      * Used by subclasses to, for example, create an attribute
 1463  
      * within a class.
 1464  
      *
 1465  
      * @param fg The fig group to which this applies
 1466  
      * @param me The input event that triggered us. In the current
 1467  
      *            implementation a mouse double click.
 1468  
      */
 1469  
     protected void createContainedModelElement(FigGroup fg, InputEvent me) {
 1470  
         // must be overridden to make sense
 1471  
         // (I didn't want to make it abstract because it might not be required)
 1472  0
     }
 1473  
 
 1474  
     /**
 1475  
      * @param o the given object
 1476  
      * @return true if one of my figs has the given object as owner
 1477  
      */
 1478  
     protected boolean isPartlyOwner(Object o) {
 1479  0
         if (o == null || o == getOwner()) {
 1480  0
             return true;
 1481  
         }
 1482  0
         for (Object fig : getFigs()) {
 1483  0
             if (isPartlyOwner((Fig) fig, o)) {
 1484  0
                 return true;
 1485  
             }
 1486  
         }
 1487  0
         return false;
 1488  
     }
 1489  
 
 1490  
     /**
 1491  
      * @param fig the given fig (may be a group)
 1492  
      * @param o the given object
 1493  
      * @return true if one of the given figs has the given object as owner
 1494  
      */
 1495  
     protected boolean isPartlyOwner(Fig fig, Object o) {
 1496  0
         if (o == null) {
 1497  0
             return false;
 1498  
         }
 1499  0
         if (o == fig.getOwner()) {
 1500  0
             return true;
 1501  
         }
 1502  0
         if (fig instanceof FigGroup) {
 1503  0
             for (Object fig2 : ((FigGroup) fig).getFigs()) {
 1504  0
                 if (isPartlyOwner((Fig) fig2, o)) {
 1505  0
                     return true;
 1506  
                 }
 1507  
             }
 1508  
         }
 1509  0
         return false;
 1510  
     }
 1511  
 
 1512  
     /*
 1513  
      * @see org.tigris.gef.presentation.Fig#deleteFromModel()
 1514  
      */
 1515  
     @Override
 1516  
     public void deleteFromModel() {
 1517  0
         Object own = getOwner();
 1518  0
         if (own != null) {
 1519  0
             getProject().moveToTrash(own);
 1520  
         }
 1521  0
         for (Object fig : getFigs()) {
 1522  0
             ((Fig) fig).deleteFromModel();
 1523  
         }
 1524  0
         super.deleteFromModel();
 1525  0
     }
 1526  
 
 1527  
     /**
 1528  
      * Replace the NotationProvider(s). <p>
 1529  
      *
 1530  
      * This method shall not be used for the initial creation of
 1531  
      * notation providers, but only for replacing them when required.
 1532  
      * Initialization must be done in the
 1533  
      * constructor using methods which
 1534  
      * can't be overridden. <p>
 1535  
      * NotationProviders can not be updated - they
 1536  
      * are lightweight throw-away objects.
 1537  
      * Hence this method creates a (new) NotationProvider whenever
 1538  
      * needed. E.g. when the notation language is
 1539  
      * changed by the user, then the NPs are to be re-created.
 1540  
      * So, this method shall not be
 1541  
      * called from a Fig constructor.<p>
 1542  
      *
 1543  
      * After the removal of the deprecated method setOwner(),
 1544  
      * this method shall contain the following statement:
 1545  
      *     assert notationProviderName != null
 1546  
      * 
 1547  
      * @param own owning UML element
 1548  
      */
 1549  
     protected void initNotationProviders(Object own) {
 1550  0
         if (notationProviderName != null) {
 1551  0
             notationProviderName.cleanListener();
 1552  
         }
 1553  0
         if (Model.getFacade().isAUMLElement(own)) {
 1554  0
             NotationName notation = Notation.findNotation(
 1555  
                     getNotationSettings().getNotationLanguage());
 1556  0
             notationProviderName =
 1557  
                 NotationProviderFactory2.getInstance().getNotationProvider(
 1558  
                         getNotationProviderType(), own, this,
 1559  
                         notation);
 1560  
         }
 1561  0
     }
 1562  
     
 1563  
     /**
 1564  
      * Overrule this for subclasses 
 1565  
      * that need a different NotationProvider.
 1566  
      * 
 1567  
      * @return the type of the notation provider
 1568  
      */
 1569  
     protected int getNotationProviderType() {
 1570  0
         return NotationProviderFactory2.TYPE_NAME;
 1571  
     }
 1572  
 
 1573  
     /**
 1574  
      * Updates the text of the stereotype FigText. Override in subclasses to get
 1575  
      * wanted behaviour.
 1576  
      */
 1577  
     protected void updateStereotypeText() {
 1578  0
         if (getOwner() == null) {
 1579  0
             LOG.warn("Null owner for [" + this.toString() + "/"
 1580  
                     + this.getClass());
 1581  0
             return;
 1582  
         }
 1583  0
         if (getStereotypeFig() != null) {
 1584  0
             getStereotypeFig().populate();
 1585  
         }
 1586  0
     }
 1587  
 
 1588  
     /**
 1589  
      * Updates the text of the name FigText.
 1590  
      * This includes text changes, 
 1591  
      * but also changes in rendering like bold.
 1592  
      */
 1593  
     protected void updateNameText() {
 1594  0
         if (readyToEdit) {
 1595  0
             if (getOwner() == null) {
 1596  0
                 return;
 1597  
             }
 1598  0
             if (notationProviderName != null) {
 1599  0
                 nameFig.setText(notationProviderName.toString(
 1600  
                         getOwner(), getNotationSettings()));
 1601  0
                 updateFont();
 1602  0
                 updateBounds();
 1603  
             }
 1604  
         }
 1605  0
     }
 1606  
 
 1607  
     /*
 1608  
      * @see org.argouml.uml.diagram.ui.PathContainer#isPathVisible()
 1609  
      */
 1610  
     public boolean isPathVisible() {
 1611  0
         return getNotationSettings().isShowPaths();
 1612  
     }
 1613  
 
 1614  
     /*
 1615  
      * @see org.argouml.uml.diagram.ui.PathContainer#setPathVisible(boolean)
 1616  
      */
 1617  
     public void setPathVisible(boolean visible) {
 1618  0
         NotationSettings ns = getNotationSettings();
 1619  0
         if (ns.isShowPaths() == visible) {
 1620  0
             return;
 1621  
         }
 1622  0
         MutableGraphSupport.enableSaveAction();
 1623  
         // TODO: Use this event mechanism to update 
 1624  
         // the checkmark on the Presentation Tab:
 1625  0
         firePropChange("pathVisible", !visible, visible);
 1626  0
         ns.setShowPaths(visible);
 1627  0
         if (readyToEdit) {
 1628  0
             renderingChanged();
 1629  0
             damage();
 1630  
         }
 1631  0
     }
 1632  
     
 1633  
     /**
 1634  
      * At creation time of the Fig, we determine 
 1635  
      * if the path should be visible by default. <p>
 1636  
      * 
 1637  
      * The path is a concatenation of the names of all packages by which 
 1638  
      * this modelelement is contained, 
 1639  
      * seperated by "::" (for UML at least). <p>
 1640  
      * 
 1641  
      * If the default namespace of the diagram corresponds 
 1642  
      * to the namespace of the modelelement, 
 1643  
      * then we do NOT show the path. Otherwise, we do. <p>
 1644  
      * 
 1645  
      * RRose uses the same heuristic algorithm, 
 1646  
      * but shows "(from &lt;path&gt;)" below the name, 
 1647  
      * while we follow the UML syntax.
 1648  
      */
 1649  
     protected void determineDefaultPathVisible() {
 1650  0
         Object modelElement = getOwner();
 1651  0
         LayerPerspective layer = (LayerPerspective) getLayer();
 1652  0
         if ((layer != null) 
 1653  
                 && Model.getFacade().isAModelElement(modelElement)) {
 1654  0
             ArgoDiagram diagram = (ArgoDiagram) layer.getDiagram();
 1655  0
             Object elementNs = Model.getFacade().getNamespace(modelElement);
 1656  0
             Object diagramNs = diagram.getNamespace();
 1657  0
             if (elementNs != null) {
 1658  0
                 boolean visible = (elementNs != diagramNs);
 1659  0
                 getNotationSettings().setShowPaths(visible);
 1660  0
                 updateNameText();
 1661  0
                 damage();
 1662  
             }
 1663  
             // it is done
 1664  
         }
 1665  
         // either layer or owner was null
 1666  0
     }
 1667  
 
 1668  
     /*
 1669  
      * @see org.tigris.gef.presentation.Fig#classNameAndBounds()
 1670  
      */
 1671  
     @Deprecated
 1672  
     @Override
 1673  
     public String classNameAndBounds() {
 1674  0
         return getClass().getName()
 1675  
             + "[" + getX() + ", " + getY() + ", "
 1676  
             + getWidth() + ", " + getHeight() + "]"
 1677  
             + "pathVisible=" + isPathVisible() + ";"
 1678  
             + "stereotypeView=" + getStereotypeView() + ";";
 1679  
     }
 1680  
 
 1681  
     /**
 1682  
      * Implementations of this method should register/unregister the fig for all
 1683  
      * (model)events. For FigNodeModelElement only the fig itself is registered
 1684  
      * as listening to (all) events fired by the owner itself. 
 1685  
      * But for, for example,
 1686  
      * FigClass the fig must also register for events fired by the operations
 1687  
      * and attributes of the owner. <p>
 1688  
      * 
 1689  
      * An explanation of the original 
 1690  
      * purpose of this method is given in issue 1321.<p>
 1691  
      * 
 1692  
      * This function is used by the modelChanged()
 1693  
      * function.<p>
 1694  
      * 
 1695  
      * In certain cases, it is imperative that indeed ALL listeners are 
 1696  
      * updated, since they are ALL removed 
 1697  
      * by a call to removeElementListener. <p>
 1698  
      * 
 1699  
      *  IF this method is called with both the oldOwner and the 
 1700  
      *  newOwner equal and not null, 
 1701  
      *  AND we listen only to the owner itself,
 1702  
      *  THEN we can safely ignore the call, but 
 1703  
      *  ELSE we need to update the listeners of the related elements, 
 1704  
      *  since the related elements may have been replaced. 
 1705  
      * 
 1706  
      * @param newOwner null, or the owner of this. 
 1707  
      *          The former means that all listeners have to be removed. 
 1708  
      * @param oldOwner null, or the previous owner
 1709  
      *          The former means that all listeners have to be set.
 1710  
      */
 1711  
     protected void updateListeners(Object oldOwner, Object newOwner) {
 1712  0
         if (oldOwner == newOwner) {
 1713  0
             return;
 1714  
         }
 1715  0
         if (oldOwner != null) {
 1716  0
             removeElementListener(oldOwner);
 1717  
         }
 1718  0
         if (newOwner != null) {
 1719  0
             addElementListener(newOwner);
 1720  
         }
 1721  
 
 1722  0
     }
 1723  
 
 1724  
     /**
 1725  
      * @see org.argouml.application.events.ArgoNotationEventListener#notationChanged(org.argouml.application.events.ArgoNotationEvent)
 1726  
      * @deprecated for 0.27.2 by tfmorris. Changes to notatation provider are
 1727  
      *             now handled by the owning diagram.
 1728  
      */
 1729  
     @Deprecated
 1730  
     public void notationChanged(ArgoNotationEvent event) {
 1731  0
         if (getOwner() == null) {
 1732  0
             return;
 1733  
         }
 1734  
         try {
 1735  0
             renderingChanged();
 1736  0
         } catch (Exception e) {
 1737  0
             LOG.error("Exception", e);
 1738  0
         }
 1739  0
     }
 1740  
 
 1741  
     /**
 1742  
      * @see org.argouml.application.events.ArgoNotationEventListener#notationAdded(org.argouml.application.events.ArgoNotationEvent)
 1743  
      * @deprecated for 0.27.2 by tfmorris.
 1744  
      */
 1745  
     @Deprecated
 1746  
     public void notationAdded(ArgoNotationEvent event) {
 1747  
         // Default is to do nothing
 1748  0
     }
 1749  
 
 1750  
     /**
 1751  
      * @see org.argouml.application.events.ArgoNotationEventListener#notationRemoved(org.argouml.application.events.ArgoNotationEvent)
 1752  
      * @deprecated for 0.27.2 by tfmorris.
 1753  
      */
 1754  
     @Deprecated
 1755  
     public void notationRemoved(ArgoNotationEvent event) {
 1756  
         // Default is to do nothing
 1757  0
     }
 1758  
 
 1759  
     /**
 1760  
      * @see org.argouml.application.events.ArgoNotationEventListener#notationProviderAdded(org.argouml.application.events.ArgoNotationEvent)
 1761  
      * @deprecated for 0.27.2 by tfmorris.
 1762  
      */
 1763  
     @Deprecated
 1764  
     public void notationProviderAdded(ArgoNotationEvent event) {
 1765  
         // Default is to do nothing
 1766  0
     }
 1767  
 
 1768  
     /**
 1769  
      * @see org.argouml.application.events.ArgoNotationEventListener#notationProviderRemoved(org.argouml.application.events.ArgoNotationEvent)
 1770  
      * @deprecated for 0.27.2 by tfmorris.
 1771  
      */
 1772  
     @Deprecated
 1773  
     public void notationProviderRemoved(ArgoNotationEvent event) {
 1774  
         // Default is to do nothing
 1775  0
     }
 1776  
 
 1777  
     /**
 1778  
      * Rerender the entire fig.
 1779  
      * <p>
 1780  
      * This is may be an expensive operation for subclasses which are complex,
 1781  
      * so should be used sparingly. This functionality was originally the
 1782  
      * functionality of modelChanged but modelChanged takes the event now into
 1783  
      * account.
 1784  
      */
 1785  
     public void renderingChanged() {
 1786  0
         initNotationProviders(getOwner());
 1787  0
         updateNameText();
 1788  0
         updateStereotypeText();
 1789  0
         updateStereotypeIcon();        
 1790  0
         updateBounds();
 1791  0
         damage();
 1792  0
     }
 1793  
 
 1794  
     protected void updateStereotypeIcon() {
 1795  0
         if (getOwner() == null) {
 1796  0
             LOG.warn("Owner of [" + this.toString() + "/" + this.getClass()
 1797  
                     + "] is null.");
 1798  0
             LOG.warn("I return...");
 1799  0
             return;
 1800  
         }
 1801  
 
 1802  0
         if (stereotypeFigProfileIcon != null) {
 1803  0
             for (Object fig : getFigs()) {
 1804  0
                 ((Fig) fig).setVisible(fig != stereotypeFigProfileIcon);
 1805  
             }
 1806  
 
 1807  0
             this.removeFig(stereotypeFigProfileIcon);
 1808  0
             stereotypeFigProfileIcon = null;
 1809  
         }
 1810  
         
 1811  0
         if (originalNameFig != null) {
 1812  0
             this.setNameFig(originalNameFig);
 1813  0
             originalNameFig = null;
 1814  
         }
 1815  
         
 1816  0
         for (Fig icon : floatingStereotypes) {
 1817  0
             this.removeFig(icon);
 1818  
         }
 1819  0
         floatingStereotypes.clear();
 1820  
 
 1821  
 
 1822  0
         int practicalView = getPracticalView();
 1823  0
         Object modelElement = getOwner();
 1824  0
         Collection stereos = Model.getFacade().getStereotypes(modelElement);
 1825  
          
 1826  0
         boolean hiding = 
 1827  
             practicalView == DiagramAppearance.STEREOTYPE_VIEW_SMALL_ICON;
 1828  0
         if (getStereotypeFig() != null) {
 1829  0
             getStereotypeFig().setHidingStereotypesWithIcon(hiding);
 1830  
         }
 1831  
 
 1832  0
         if (practicalView == DiagramAppearance.STEREOTYPE_VIEW_BIG_ICON) {
 1833  
 
 1834  0
             Image replaceIcon = null;
 1835  
 
 1836  0
             if (stereos.size() == 1) {
 1837  0
                 Object stereo = stereos.iterator().next();
 1838  
                 // TODO: Find a way to replace this dependency on Project
 1839  0
                 replaceIcon = getProject()
 1840  
                         .getProfileConfiguration().getFigNodeStrategy()
 1841  
                         .getIconForStereotype(stereo);
 1842  
             }
 1843  
 
 1844  0
             if (replaceIcon != null) {
 1845  0
                 stereotypeFigProfileIcon = new FigProfileIcon(settings,
 1846  
                         replaceIcon, getName());
 1847  0
                 stereotypeFigProfileIcon.setOwner(getOwner());
 1848  
 
 1849  0
                 stereotypeFigProfileIcon.setLocation(getBigPort()
 1850  
                         .getLocation());
 1851  0
                 addFig(stereotypeFigProfileIcon);
 1852  
 
 1853  0
                 originalNameFig = this.getNameFig();
 1854  0
                 final FigText labelFig =
 1855  
                     stereotypeFigProfileIcon.getLabelFig();
 1856  0
                 setNameFig(labelFig);
 1857  
 
 1858  0
                 labelFig.addPropertyChangeListener(this);
 1859  
 
 1860  0
                 getBigPort().setBounds(stereotypeFigProfileIcon.getBounds());
 1861  
 
 1862  0
                 for (Object fig : getFigs()) {
 1863  0
                     ((Fig) fig).setVisible(fig == stereotypeFigProfileIcon);
 1864  
                 }
 1865  
 
 1866  
             }
 1867  0
         } else if (practicalView
 1868  
                 == DiagramAppearance.STEREOTYPE_VIEW_SMALL_ICON) {
 1869  0
             int i = this.getX() + this.getWidth() - ICON_WIDTH - 2;
 1870  
 
 1871  0
             for (Object stereo : stereos) {
 1872  
                 // TODO: Find a way to replace this dependency on Project
 1873  0
                 Image icon = getProject()
 1874  
                         .getProfileConfiguration().getFigNodeStrategy()
 1875  
                         .getIconForStereotype(stereo);
 1876  0
                 if (icon != null) {
 1877  0
                     FigImage fimg = new FigImage(i,
 1878  
                             this.getBigPort().getY() + 2, icon);
 1879  0
                     fimg.setSize(ICON_WIDTH,
 1880  
                             (icon.getHeight(null) * ICON_WIDTH)
 1881  
                                     / icon.getWidth(null));
 1882  
 
 1883  0
                     addFig(fimg);
 1884  0
                     floatingStereotypes.add(fimg);
 1885  
 
 1886  0
                     i -= ICON_WIDTH - 2;
 1887  
                 }
 1888  0
             }
 1889  
 
 1890  0
             updateSmallIcons(this.getWidth());
 1891  
         }
 1892  
 
 1893  
         // TODO: This is a redundant invocation
 1894  0
         updateStereotypeText();
 1895  
         
 1896  0
         damage();
 1897  0
         calcBounds();
 1898  0
         updateEdges();
 1899  0
         updateBounds();
 1900  0
         redraw();
 1901  0
     }
 1902  
 
 1903  
     /*
 1904  
      * @see org.tigris.gef.presentation.Fig#calcBounds()
 1905  
      */
 1906  
     public void calcBounds() {
 1907  2142
         if (suppressCalcBounds) {
 1908  0
             return;
 1909  
         }
 1910  2142
         super.calcBounds();
 1911  2142
     }
 1912  
 
 1913  
     /**
 1914  
      * The setter for checkSize.
 1915  
      *
 1916  
      * @param flag the new value
 1917  
      */
 1918  
     public void enableSizeChecking(boolean flag) {
 1919  0
         checkSize = flag;
 1920  0
     }
 1921  
 
 1922  
     /*
 1923  
      * Necessary since GEF contains some errors regarding the hit subject.
 1924  
      * 
 1925  
      * @see org.tigris.gef.presentation.Fig#hit(Rectangle)
 1926  
      */
 1927  
     @Override
 1928  
     public boolean hit(Rectangle r) {
 1929  0
         int cornersHit = countCornersContained(r.x, r.y, r.width, r.height);
 1930  0
         if (_filled) {
 1931  0
             return cornersHit > 0 || intersects(r);
 1932  
         }
 1933  0
         return (cornersHit > 0 && cornersHit < 4) || intersects(r);
 1934  
     }
 1935  
 
 1936  
     /*
 1937  
      * @see org.tigris.gef.presentation.Fig#removeFromDiagram()
 1938  
      */
 1939  
     @Override
 1940  
     public final void removeFromDiagram() {
 1941  0
         Fig delegate = getRemoveDelegate();
 1942  0
         if (delegate instanceof FigNodeModelElement) {
 1943  0
             ((FigNodeModelElement) delegate).removeFromDiagramImpl();
 1944  0
         } else if (delegate instanceof FigEdgeModelElement) {
 1945  0
             ((FigEdgeModelElement) delegate).removeFromDiagramImpl();
 1946  0
         } else if (delegate != null) {
 1947  0
             removeFromDiagramImpl();
 1948  
         }
 1949  0
     }
 1950  
     
 1951  
     /**
 1952  
      * Subclasses should override this to redirect a remove request from
 1953  
      * one Fig to another.
 1954  
      * e.g. FigClassAssociationClass uses this to delegate the remove to
 1955  
      * its attached FigAssociationClass.
 1956  
      * @return the fig that handles the remove request
 1957  
      */
 1958  
     protected Fig getRemoveDelegate() {
 1959  0
         return this;
 1960  
     }
 1961  
     
 1962  
     /**
 1963  
      * If you override this method, make sure to remove all listeners:
 1964  
      * If you don't, objects in a deleted project will still receive events.<p>
 1965  
      * 
 1966  
      * Also important for remove from diagram!
 1967  
      */
 1968  
     protected void removeFromDiagramImpl() {
 1969  0
         if (notationProviderName != null) { //This test needed for a FigPool
 1970  0
             notationProviderName.cleanListener();
 1971  
         }
 1972  0
         removeAllElementListeners();
 1973  0
         setShadowSize(0);
 1974  0
         super.removeFromDiagram();
 1975  
         // Get model listeners removed:
 1976  0
         if (getStereotypeFig() != null) {
 1977  0
             getStereotypeFig().removeFromDiagram();
 1978  
         }
 1979  0
     }
 1980  
 
 1981  
     /**
 1982  
      * Get the Fig containing the stereotype(s).
 1983  
      *
 1984  
      * @return the stereotype FigGroup
 1985  
      */
 1986  
     protected FigStereotypesGroup getStereotypeFig() {
 1987  0
         return stereotypeFig;
 1988  
     }
 1989  
 
 1990  
 
 1991  
     /**
 1992  
      * @param bp the bigPort, which is the port where edges 
 1993  
      *          connect to this node
 1994  
      * @deprecated by MVW since V0.28.1. Use {@link #createBigPortFig} 
 1995  
      *          instead, to guarantee correct initialization.
 1996  
      */
 1997  
     protected void setBigPort(Fig bp) {
 1998  0
         this.bigPort = bp;
 1999  0
         bindPort(getOwner(), bigPort);
 2000  0
     }
 2001  
 
 2002  
     /**
 2003  
      * @return the fig which is the port where edges connect to this node
 2004  
      */
 2005  
     public Fig getBigPort() {
 2006  1071
         return bigPort;
 2007  
     }
 2008  
 
 2009  
     /**
 2010  
      * @return Returns the checkSize.
 2011  
      */
 2012  
     protected boolean isCheckSize() {
 2013  0
         return checkSize;
 2014  
     }
 2015  
 
 2016  
     /*
 2017  
      * @see org.tigris.gef.presentation.FigNode#isDragConnectable()
 2018  
      */
 2019  
     public boolean isDragConnectable() {
 2020  0
         return false;
 2021  
     }
 2022  
 
 2023  
     /**
 2024  
      * @param e The _encloser to set.
 2025  
      */
 2026  
     protected void setEncloser(Fig e) {
 2027  0
         this.encloser = e;
 2028  0
     }
 2029  
 
 2030  
     /**
 2031  
      * @return Returns the _encloser.
 2032  
      */
 2033  
     protected Fig getEncloser() {
 2034  0
         return encloser;
 2035  
     }
 2036  
     /**
 2037  
      * @return Returns the ReadyToEdit.
 2038  
      */
 2039  
     protected boolean isReadyToEdit() {
 2040  0
         return readyToEdit;
 2041  
     }
 2042  
 
 2043  
     /**
 2044  
      * @param v if ready to edit
 2045  
      */
 2046  
     protected void setReadyToEdit(boolean v) {
 2047  0
         readyToEdit = v;
 2048  0
     }
 2049  
 
 2050  
     /**
 2051  
      * TODO: Move this in FigGroup (in GEF).
 2052  
      * 
 2053  
      * @param scb The suppressCalcBounds to set.
 2054  
      */
 2055  
     protected void setSuppressCalcBounds(boolean scb) {
 2056  0
         this.suppressCalcBounds = scb;
 2057  0
     }
 2058  
     
 2059  
     /**
 2060  
      * Set visibility of figure. If the field {@link #invisibleAllowed} is not
 2061  
      * <code>true</code> and this method is passed a parameter of
 2062  
      * <code>false</code> it will throw an IllegalArgumentException.
 2063  
      * 
 2064  
      * @param visible
 2065  
      *            new visibility - <code>true</code> = visible.
 2066  
      * 
 2067  
      * @see org.tigris.gef.presentation.Fig#setVisible(boolean)
 2068  
      */
 2069  
     public void setVisible(boolean visible) {
 2070  0
         if (!visible && !invisibleAllowed) {
 2071  0
             throw new IllegalArgumentException(
 2072  
                     "Visibility of a FigNode should never be false");
 2073  
         }
 2074  0
     }
 2075  
 
 2076  
     /**
 2077  
      * To redraw each element correctly when changing its location
 2078  
      * with X and Y additions. Also manages relocation of enclosed
 2079  
      * Figs.
 2080  
      *
 2081  
      * @param xInc the increment in the x direction
 2082  
      * @param yInc the increment in the y direction
 2083  
      */
 2084  
     public void displace (int xInc, int yInc) {
 2085  
         List<Fig> figsVector;
 2086  0
         Rectangle rFig = getBounds();
 2087  0
         setLocation(rFig.x + xInc, rFig.y + yInc);
 2088  0
         figsVector = ((List<Fig>) getEnclosedFigs().clone());
 2089  0
         if (!figsVector.isEmpty()) {
 2090  0
             for (int i = 0; i < figsVector.size(); i++) {
 2091  0
                 ((FigNodeModelElement) figsVector.get(i))
 2092  
                             .displace(xInc, yInc);
 2093  
             }
 2094  
         }
 2095  0
     }
 2096  
 
 2097  
 
 2098  
     /**
 2099  
      * @param allowed true if the function RemoveFromDiagram is allowed
 2100  
      */
 2101  
     protected void allowRemoveFromDiagram(boolean allowed) {
 2102  0
         this.removeFromDiagram = allowed;
 2103  0
     }
 2104  
 
 2105  
     public void setDiElement(DiElement element) {
 2106  0
         this.diElement = element;
 2107  0
     }
 2108  
 
 2109  
     public DiElement getDiElement() {
 2110  0
         return diElement;
 2111  
     }
 2112  
 
 2113  
     /**
 2114  
      * @return Returns the popupAddOffset.
 2115  
      */
 2116  
     protected static int getPopupAddOffset() {
 2117  0
         return popupAddOffset;
 2118  
     }
 2119  
 
 2120  
     /**
 2121  
      * Determine if this node can be edited.
 2122  
      * @return editable state
 2123  
      */
 2124  
     public boolean isEditable() {
 2125  0
         return editable;
 2126  
     }
 2127  
 
 2128  
     /**
 2129  
      * By default a node is directly editable by simply selecting
 2130  
      * that node and starting to type.
 2131  
      * Should a subclass of FigNodeModelElement not desire this behaviour
 2132  
      * then it should call setEditable(false) in its constructor.
 2133  
      * 
 2134  
      * @param canEdit new state, false = editing disabled.
 2135  
      */
 2136  
     protected void setEditable(boolean canEdit) {
 2137  0
         this.editable = canEdit;
 2138  0
     }
 2139  
 
 2140  
     /**
 2141  
      * Add an element listener and remember the registration.
 2142  
      * 
 2143  
      * @param element
 2144  
      *            element to listen for changes on
 2145  
      * @see org.argouml.model.ModelEventPump#addModelEventListener(PropertyChangeListener, Object, String)
 2146  
      */
 2147  
     protected void addElementListener(Object element) {
 2148  0
         listeners.add(new Object[] {element, null});
 2149  0
         Model.getPump().addModelEventListener(this, element);
 2150  0
     }
 2151  
     
 2152  
     /**
 2153  
      * Add a listener for a given property name and remember the registration.
 2154  
      * 
 2155  
      * @param element
 2156  
      *            element to listen for changes on
 2157  
      * @param property
 2158  
      *            name of property to listen for changes of
 2159  
      * @see org.argouml.model.ModelEventPump#addModelEventListener(PropertyChangeListener,
 2160  
      *      Object, String)
 2161  
      */
 2162  
     protected void addElementListener(Object element, String property) {
 2163  0
         listeners.add(new Object[] {element, property});
 2164  0
         Model.getPump().addModelEventListener(this, element, property);
 2165  0
     }
 2166  
 
 2167  
     /**
 2168  
      * Add a listener for an array of property names and remember the
 2169  
      * registration.
 2170  
      * 
 2171  
      * @param element
 2172  
      *            element to listen for changes on
 2173  
      * @param property
 2174  
      *            array of property names (Strings) to listen for changes of
 2175  
      * @see org.argouml.model.ModelEventPump#addModelEventListener(PropertyChangeListener,
 2176  
      *      Object, String)
 2177  
      */
 2178  
     protected void addElementListener(Object element, String[] property) {
 2179  0
         listeners.add(new Object[] {element, property});
 2180  0
         Model.getPump().addModelEventListener(this, element, property);
 2181  0
     }
 2182  
     
 2183  
     /**
 2184  
      * Remove an element listener and remembered registration.
 2185  
      * 
 2186  
      * @param element
 2187  
      *            element to listen for changes on
 2188  
      * @see org.argouml.model.ModelEventPump#addModelEventListener(PropertyChangeListener, Object, String)
 2189  
      */
 2190  
     protected void removeElementListener(Object element) {
 2191  0
         listeners.remove(new Object[] {element, null});
 2192  0
         Model.getPump().removeModelEventListener(this, element);
 2193  0
     }
 2194  
     
 2195  
     /**
 2196  
      * Unregister all listeners registered through addElementListener
 2197  
      * @see #addElementListener(Object, String)
 2198  
      */
 2199  
     protected void removeAllElementListeners() {
 2200  0
         removeElementListeners(listeners);
 2201  0
     }
 2202  
 
 2203  
     private void removeElementListeners(Set<Object[]> listenerSet) {
 2204  0
         for (Object[] listener : listenerSet) {
 2205  0
             Object property = listener[1];
 2206  0
             if (property == null) {
 2207  0
                 Model.getPump().removeModelEventListener(this, listener[0]);
 2208  0
             } else if (property instanceof String[]) {
 2209  0
                 Model.getPump().removeModelEventListener(this, listener[0],
 2210  
                         (String[]) property);
 2211  0
             } else if (property instanceof String) {
 2212  0
                 Model.getPump().removeModelEventListener(this, listener[0],
 2213  
                         (String) property);
 2214  
             } else {
 2215  0
                 throw new RuntimeException(
 2216  
                         "Internal error in removeAllElementListeners");
 2217  
             }
 2218  0
         }
 2219  0
         listeners.removeAll(listenerSet);
 2220  0
     }
 2221  
 
 2222  
     private void addElementListeners(Set<Object[]> listenerSet) {
 2223  0
         for (Object[] listener : listenerSet) {
 2224  0
             Object property = listener[1];
 2225  0
             if (property == null) {
 2226  0
                 addElementListener(listener[0]);
 2227  0
             } else if (property instanceof String[]) {
 2228  0
                 addElementListener(listener[0], (String[]) property);
 2229  0
             } else if (property instanceof String) {
 2230  0
                 addElementListener(listener[0], (String) property);
 2231  
             } else {
 2232  0
                 throw new RuntimeException(
 2233  
                         "Internal error in addElementListeners");
 2234  
             }
 2235  0
         }
 2236  0
     }
 2237  
 
 2238  
     /**
 2239  
      * Update the set of registered listeners to match the given set using 
 2240  
      * a minimal update strategy to remove unneeded listeners and add new 
 2241  
      * listeners.
 2242  
      * 
 2243  
      * @param listenerSet a set of arrays containing a tuple of a UML element
 2244  
      * to be listened to and a set of property to be listened for.  
 2245  
      */
 2246  
     protected void updateElementListeners(Set<Object[]> listenerSet) {
 2247  0
         Set<Object[]> removes = new HashSet<Object[]>(listeners);
 2248  0
         removes.removeAll(listenerSet);
 2249  0
         removeElementListeners(removes);
 2250  
         
 2251  0
         Set<Object[]> adds = new HashSet<Object[]>(listenerSet);
 2252  0
         adds.removeAll(listeners);
 2253  0
         addElementListeners(adds);
 2254  0
     }
 2255  
 
 2256  
     /**
 2257  
      * This optional method is not implemented.  It will throw an
 2258  
      * {@link UnsupportedOperationException} if used.  Figs are 
 2259  
      * added to a GraphModel which is, in turn, owned by a project.<p>
 2260  
      * 
 2261  
      * @param project the project
 2262  
      * @deprecated
 2263  
      */
 2264  
     @SuppressWarnings("deprecation")
 2265  
     @Deprecated
 2266  
     public void setProject(Project project) {
 2267  0
         throw new UnsupportedOperationException();
 2268  
     }
 2269  
     
 2270  
     /**
 2271  
      * @deprecated for 0.27.2 by tfmorris.  Implementations should have all
 2272  
      * the information that they require in the DiagramSettings object.
 2273  
      * 
 2274  
      * @return the owning project
 2275  
      * @see org.argouml.uml.diagram.ui.ArgoFig#getProject()
 2276  
      */
 2277  
     @Deprecated
 2278  
     public Project getProject() {
 2279  0
         return ArgoFigUtil.getProject(this);
 2280  
     }
 2281  
     
 2282  
     /**
 2283  
      * Determine if this Fig is the sole selected target in
 2284  
      * the TargetManager
 2285  
      * @return true if this is the sole target.
 2286  
      */
 2287  
     protected boolean isSingleTarget() {
 2288  0
         return TargetManager.getInstance().getSingleModelTarget()
 2289  
                 == getOwner();
 2290  
     }
 2291  
 
 2292  
     
 2293  
     /**
 2294  
      * @return current stereotype view
 2295  
      * @deprecated for 0.27.2 by tfmorris.  Use {@link #getStereotypeStyle()}.
 2296  
      */
 2297  
     public int getStereotypeView() {
 2298  0
         return stereotypeStyle.ordinal();
 2299  
     }
 2300  
     
 2301  
     /**
 2302  
      * @return
 2303  
      * @see org.argouml.uml.diagram.ui.StereotypeStyled#getStereotypeStyle()
 2304  
      */
 2305  
     public StereotypeStyle getStereotypeStyle() {
 2306  0
         return stereotypeStyle;
 2307  
     }
 2308  
 
 2309  
     /**
 2310  
      * Return a stereotype view which is most practical for the current
 2311  
      * conditions. If the current mode is set to <code>BigIcon</code> mode and
 2312  
      * the model element has zero or more than one stereotype the practical view
 2313  
      * should be the textual view.
 2314  
      * 
 2315  
      * @return current practical stereotype view
 2316  
      */
 2317  
     private int getPracticalView() {
 2318  
         // TODO assert modelElement != null???
 2319  0
         int practicalView = getStereotypeView();
 2320  0
         Object modelElement = getOwner();
 2321  
 
 2322  0
         if (modelElement != null) {
 2323  0
             int stereotypeCount = getStereotypeCount();
 2324  
 
 2325  0
             if (getStereotypeView()
 2326  
                     == DiagramAppearance.STEREOTYPE_VIEW_BIG_ICON) {
 2327  
                 // TODO: Find a way to replace this dependency on Project
 2328  0
                 FigNodeStrategy figNodeStrategy = getProject()
 2329  
                     .getProfileConfiguration().getFigNodeStrategy();
 2330  0
                 Iterator<FigStereotype> figsIterator = getStereotypeFig()
 2331  
                     .getStereotypeFigs().iterator();
 2332  0
                 Object owner = figsIterator.hasNext() ?
 2333  
                         figsIterator.next().getOwner() : null;
 2334  0
                 if (stereotypeCount != 1
 2335  
                         || figNodeStrategy == null
 2336  
                         || owner == null
 2337  
                         ||  (stereotypeCount == 1
 2338  
                                 && figNodeStrategy.getIconForStereotype(owner) 
 2339  
                                     == null)) {
 2340  0
                 practicalView = DiagramAppearance.STEREOTYPE_VIEW_TEXTUAL;
 2341  
                 }
 2342  
             }
 2343  
         }
 2344  0
         return practicalView;
 2345  
     }
 2346  
     
 2347  
     /**
 2348  
      * Get the number of stereotypes contained in this FigNode
 2349  
      * @return the number of stereotypes contained in the FigNode
 2350  
      */
 2351  
     public int getStereotypeCount() {
 2352  0
         if (getStereotypeFig() == null) {
 2353  0
             return 0;
 2354  
         }
 2355  0
         return getStereotypeFig().getStereotypeCount();
 2356  
     }
 2357  
     
 2358  
     /**
 2359  
      * Sets the stereotype view.
 2360  
      * 
 2361  
      * @param s the stereotype view to be set
 2362  
      * @deprecated for 0.27.2 by tfmorris.  Use 
 2363  
      * {@link #setStereotypeStyle(StereotypeStyle)}.
 2364  
      */
 2365  
     public void setStereotypeView(int s) {
 2366  0
         setStereotypeStyle(StereotypeStyle.getEnum(s));
 2367  0
     }
 2368  
 
 2369  
     /**
 2370  
      * Set the stereotype style to be used for rendering this fig.
 2371  
      * 
 2372  
      * @param style the stereotype style to be set
 2373  
      */
 2374  
     public void setStereotypeStyle(StereotypeStyle style) {
 2375  0
         stereotypeStyle = style;
 2376  0
         renderingChanged();
 2377  0
     }
 2378  
     
 2379  
     /**
 2380  
      * Sets the bounds of this node taking the stereotype view into 
 2381  
      * consideration.<br>
 2382  
      * 
 2383  
      * Do not override this method, override 
 2384  
      * {@link #setStandardBounds(int, int, int, int)} instead.
 2385  
      * 
 2386  
      * {@inheritDoc}
 2387  
      */
 2388  
     @Override
 2389  
     protected void setBoundsImpl(final int x, final int y, final int w,
 2390  
             final int h) {
 2391  
 
 2392  0
         if (getPracticalView() == DiagramAppearance.STEREOTYPE_VIEW_BIG_ICON) {
 2393  0
             if (stereotypeFigProfileIcon != null) {
 2394  0
                 stereotypeFigProfileIcon.setBounds(stereotypeFigProfileIcon
 2395  
                         .getX(), stereotypeFigProfileIcon.getY(), w, h);
 2396  
                 // FigClass calls setBoundsImpl before we set
 2397  
                 // the stereotypeFigProfileIcon
 2398  
             }
 2399  
         } else {
 2400  0
             setStandardBounds(x, y, w, h);
 2401  0
             if (getStereotypeView()
 2402  
                     == DiagramAppearance.STEREOTYPE_VIEW_SMALL_ICON) {
 2403  0
                 updateSmallIcons(w);
 2404  
             }
 2405  
         }
 2406  0
     }
 2407  
 
 2408  
     private void updateSmallIcons(int wid) {
 2409  0
         int i = this.getX() + wid - ICON_WIDTH - 2;
 2410  
 
 2411  0
         for (Fig ficon : floatingStereotypes) {
 2412  0
             ficon.setLocation(i, this.getBigPort().getY() + 2);
 2413  0
             i -= ICON_WIDTH - 2;
 2414  
         }
 2415  
 
 2416  0
         getNameFig().setRightMargin(
 2417  
                 floatingStereotypes.size() * (ICON_WIDTH + 5));
 2418  0
     }
 2419  
 
 2420  
     /**
 2421  
      * Returns the minimum size of the Fig. This is the smallest size that the
 2422  
      * user can make this Fig by dragging. <p>
 2423  
      *  
 2424  
      * Do not call this function if the Fig is not resizable!
 2425  
      * In ArgoUML we decided that it is not needed to implement 
 2426  
      * suitable getMinimumSize() methods
 2427  
      * for Figs that are not resizable.
 2428  
      */
 2429  
     @Override
 2430  
     public Dimension getMinimumSize() {
 2431  0
         assert isResizable();
 2432  0
         return super.getMinimumSize();
 2433  
     }
 2434  
 
 2435  
     /**
 2436  
      * Replaces {@link #setBoundsImpl(int, int, int, int)}.
 2437  
      * 
 2438  
      * @param x Desired X coordinate of upper left corner
 2439  
      * @param y Desired Y coordinate of upper left corner
 2440  
      * @param w Desired width of the FigClass
 2441  
      * @param h Desired height of the FigClass
 2442  
      * @see org.tigris.gef.presentation.Fig#setBoundsImpl(int, int, int, int)
 2443  
      */
 2444  
     protected void setStandardBounds(final int x, final int y,
 2445  
             final int w, final int h) {
 2446  
 
 2447  0
     }
 2448  
     
 2449  
     /**
 2450  
      * Handles diagram font changing.
 2451  
      * @param e the event or null
 2452  
      * @see org.argouml.application.events.ArgoDiagramAppearanceEventListener#diagramFontChanged(org.argouml.application.events.ArgoDiagramAppearanceEvent)
 2453  
      * @deprecated for 0.27.2 by tfmorris.  The owning diagram manages global
 2454  
      * changes to rendering defaults.
 2455  
      */
 2456  
     public void diagramFontChanged(ArgoDiagramAppearanceEvent e) {
 2457  0
         updateFont();
 2458  0
         updateBounds();
 2459  0
         damage();
 2460  0
     }
 2461  
 
 2462  
     /**
 2463  
      * This function should, for all FigTexts, 
 2464  
      * recalculate the font-style (plain, bold, italic, bold/italic),
 2465  
      * and apply it by calling FigText.setFont(). <p>
 2466  
      * 
 2467  
      * If the "deepUpdateFont" function does not 
 2468  
      * work for a subclass, then override this method.
 2469  
      */
 2470  
     protected void updateFont() {
 2471  0
         int style = getNameFigFontStyle();
 2472  0
         Font f = getSettings().getFont(style);
 2473  0
         nameFig.setFont(f);
 2474  0
         deepUpdateFont(this);
 2475  0
     }
 2476  
 
 2477  
     /**
 2478  
      * Determines the font style based on the UML model. 
 2479  
      * Overrule this in Figs that have to show bold or italic based on the 
 2480  
      * UML model they represent. 
 2481  
      * E.g. abstract classes show their name in italic.
 2482  
      * 
 2483  
      * @return the font style for the nameFig.
 2484  
      */
 2485  
     protected int getNameFigFontStyle() {
 2486  
         // TODO: Why do we need this when we can just change the font and 
 2487  
         // achieve the same effect?
 2488  0
         showBoldName = getSettings().isShowBoldNames();
 2489  0
         return showBoldName ? Font.BOLD : Font.PLAIN;
 2490  
     }
 2491  
 
 2492  
     /**
 2493  
      * Changes the font for all Figs contained in the given FigGroup. <p>
 2494  
      * 
 2495  
      *  TODO: In fact, there is a design error in this method:
 2496  
      *  E.g. for a class, if the name is Italic since the class is abstract,
 2497  
      *  then the classes features should be in Plain font.
 2498  
      *  This problem can be fixed by implementing 
 2499  
      *  the updateFont() method in all subclasses.
 2500  
      *  
 2501  
      * @param fg the FigGroup to change the font of.
 2502  
      */
 2503  
     private void deepUpdateFont(FigGroup fg) {
 2504  
         // TODO: Fonts shouldn't be handled any differently than other 
 2505  
         // rendering attributes
 2506  0
         boolean changed = false;
 2507  0
         List<Fig> figs = fg.getFigs();
 2508  0
         for (Fig f : figs) {
 2509  0
             if (f instanceof ArgoFigText) {
 2510  0
                 ((ArgoFigText) f).renderingChanged();
 2511  0
                 changed = true;
 2512  
             }
 2513  0
             if (f instanceof FigGroup) {
 2514  0
                 deepUpdateFont((FigGroup) f);
 2515  
             }
 2516  
         }
 2517  0
         if (changed) {
 2518  0
             fg.calcBounds();
 2519  
         }
 2520  0
     }
 2521  
     
 2522  
 
 2523  
     public DiagramSettings getSettings() {
 2524  
         // TODO: This is a temporary crutch to use until all Figs are updated
 2525  
         // to use the constructor that accepts a DiagramSettings object
 2526  3213
         if (settings == null) {
 2527  0
             LOG.debug("Falling back to project-wide settings");
 2528  0
             Project p = getProject();
 2529  0
             if (p != null) {
 2530  0
                 return p.getProjectSettings().getDefaultDiagramSettings();
 2531  
             }
 2532  
         }
 2533  3213
         return settings;
 2534  
     }
 2535  
     
 2536  
     public void setSettings(DiagramSettings renderSettings) {
 2537  0
         settings = renderSettings;
 2538  0
         renderingChanged();
 2539  0
     }
 2540  
 
 2541  
     protected NotationSettings getNotationSettings() {
 2542  0
         return notationSettings;
 2543  
     }
 2544  
 
 2545  
     public void setLineWidth(int w) {
 2546  0
         super.setLineWidth(w);
 2547  
         // Default for name and stereotype is no border
 2548  0
         getNameFig().setLineWidth(0);
 2549  0
         if (getStereotypeFig() != null) {
 2550  0
             getStereotypeFig().setLineWidth(0);
 2551  
         }
 2552  0
     }
 2553  
     
 2554  
     /**
 2555  
      * A default "clarifier" to be used for selection if the subclass doesn't
 2556  
      * override makeSelection and provide its own.
 2557  
      */
 2558  0
     class SelectionDefaultClarifiers extends SelectionNodeClarifiers2 {
 2559  
         
 2560  
         /** Construct a new SelectionNodeClarifiers for the given Fig
 2561  
          *
 2562  
          * @param f the given Fig
 2563  
          */
 2564  0
         private SelectionDefaultClarifiers(Fig f) {
 2565  0
             super(f);
 2566  0
         }
 2567  
 
 2568  
         @Override
 2569  
         protected Icon[] getIcons() {
 2570  0
             return null;
 2571  
         }
 2572  
 
 2573  
         @Override
 2574  
         protected String getInstructions(int index) {
 2575  0
             return null;
 2576  
         }
 2577  
 
 2578  
         @Override
 2579  
         protected Object getNewNodeType(int index) {
 2580  0
             return null;
 2581  
         }
 2582  
 
 2583  
         @Override
 2584  
         protected Object getNewEdgeType(int index) {
 2585  0
             return null;
 2586  
         }
 2587  
 
 2588  
         @Override
 2589  
         protected boolean isReverseEdge(int index) {
 2590  0
             return false;
 2591  
         }
 2592  
     }
 2593  
     
 2594  
 
 2595  
     /**
 2596  
      * Setting the owner of the Fig must be done in the constructor and not
 2597  
      * changed afterwards for all ArgoUML figs.
 2598  
      * 
 2599  
      * @param owner owning UML element
 2600  
      * @see org.tigris.gef.presentation.Fig#setOwner(java.lang.Object)
 2601  
      * @throws UnsupportedOperationException
 2602  
      * @deprecated for 0.27.3 by tfmorris. Set owner in constructor. This method
 2603  
      *             is implemented in GEF, so we'll leave this implementation
 2604  
      *             here to block any attempts to use it within ArgoUML.
 2605  
      */
 2606  
     @SuppressWarnings("deprecation")
 2607  
     @Deprecated
 2608  
     public void setOwner(Object owner) {
 2609  0
         if (owner != getOwner()) {
 2610  0
             throw new UnsupportedOperationException(
 2611  
                     "Owner must be set in constructor and left unchanged");
 2612  
         }
 2613  0
     }
 2614  
     
 2615  
     /*
 2616  
      * Override FigNode implementation to keep setOwner from getting called.
 2617  
      */
 2618  
     @Override
 2619  
     public void bindPort(Object port, Fig f) {
 2620  0
         if (f.getOwner() != port) {
 2621  0
             f.setOwner(port);
 2622  
         }
 2623  0
     }
 2624  
     
 2625  
     public void notationRenderingChanged(NotationProvider np, String rendering) {
 2626  0
         if (notationProviderName == np) {
 2627  0
             nameFig.setText(rendering);
 2628  0
             updateBounds();
 2629  0
             damage();
 2630  
         }
 2631  0
     }
 2632  
 
 2633  
     public NotationSettings getNotationSettings(NotationProvider np) {
 2634  0
         if (notationProviderName == np) {
 2635  0
             return getNotationSettings();
 2636  
         }
 2637  0
         return null;
 2638  
     }
 2639  
 
 2640  
     public Object getOwner(NotationProvider np) {
 2641  0
         if (notationProviderName == np) {
 2642  0
             return getOwner();
 2643  
         }
 2644  0
         return null;
 2645  
     }
 2646  
 }