Coverage Report - org.argouml.uml.diagram.static_structure.ui.FigPackage
 
Classes in this File Line Coverage Branch Coverage Complexity
FigPackage
0%
0/220
0%
0/78
2.1
FigPackage$FigPackageFigText
0%
0/40
0%
0/20
2.1
FigPackage$HideStereotypeAction
0%
0/6
N/A
2.1
FigPackage$HideVisibilityAction
0%
0/6
N/A
2.1
FigPackage$PackageBackground
0%
0/42
N/A
2.1
FigPackage$ShowStereotypeAction
0%
0/6
N/A
2.1
FigPackage$ShowVisibilityAction
0%
0/6
N/A
2.1
PackagePortFigRect
0%
0/13
N/A
2.1
 
 1  
 /* $Id: FigPackage.java 18728 2010-09-10 09:29:47Z 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  
  *    Bob Tarling
 11  
  *    Michiel van der Wulp
 12  
  *****************************************************************************
 13  
  *
 14  
  * Some portions of this file was previously release using the BSD License:
 15  
  */
 16  
 
 17  
 // Copyright (c) 1996-2009 The Regents of the University of California. All
 18  
 // Rights Reserved. Permission to use, copy, modify, and distribute this
 19  
 // software and its documentation without fee, and without a written
 20  
 // agreement is hereby granted, provided that the above copyright notice
 21  
 // and this paragraph appear in all copies.  This software program and
 22  
 // documentation are copyrighted by The Regents of the University of
 23  
 // California. The software program and documentation are supplied "AS
 24  
 // IS", without any accompanying services from The Regents. The Regents
 25  
 // does not warrant that the operation of the program will be
 26  
 // uninterrupted or error-free. The end-user understands that the program
 27  
 // was developed for research purposes and is advised not to rely
 28  
 // exclusively on the program for any reason.  IN NO EVENT SHALL THE
 29  
 // UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
 30  
 // SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS,
 31  
 // ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
 32  
 // THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
 33  
 // SUCH DAMAGE. THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY
 34  
 // WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 35  
 // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
 36  
 // PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF
 37  
 // CALIFORNIA HAS NO OBLIGATIONS TO PROVIDE MAINTENANCE, SUPPORT,
 38  
 // UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
 39  
 
 40  
 package org.argouml.uml.diagram.static_structure.ui;
 41  
 
 42  
 import java.awt.Color;
 43  
 import java.awt.Dimension;
 44  
 import java.awt.Point;
 45  
 import java.awt.Polygon;
 46  
 import java.awt.Rectangle;
 47  
 import java.awt.event.ActionEvent;
 48  
 import java.awt.event.MouseEvent;
 49  
 import java.beans.PropertyChangeEvent;
 50  
 import java.beans.PropertyVetoException;
 51  
 import java.util.List;
 52  
 import java.util.Vector;
 53  
 
 54  
 import javax.swing.JOptionPane;
 55  
 
 56  
 import org.apache.log4j.Logger;
 57  
 import org.argouml.application.helpers.ResourceLoaderWrapper;
 58  
 import org.argouml.i18n.Translator;
 59  
 import org.argouml.kernel.Project;
 60  
 import org.argouml.model.Model;
 61  
 import org.argouml.model.RemoveAssociationEvent;
 62  
 import org.argouml.ui.ArgoJMenu;
 63  
 import org.argouml.ui.UndoableAction;
 64  
 import org.argouml.ui.explorer.ExplorerEventAdaptor;
 65  
 import org.argouml.ui.targetmanager.TargetManager;
 66  
 import org.argouml.uml.diagram.ArgoDiagram;
 67  
 import org.argouml.uml.diagram.DiagramFactory;
 68  
 import org.argouml.uml.diagram.DiagramFactory.DiagramType;
 69  
 import org.argouml.uml.diagram.DiagramSettings;
 70  
 import org.argouml.uml.diagram.StereotypeContainer;
 71  
 import org.argouml.uml.diagram.VisibilityContainer;
 72  
 import org.argouml.uml.diagram.ui.ArgoFig;
 73  
 import org.argouml.uml.diagram.ui.ArgoFigText;
 74  
 import org.argouml.uml.diagram.ui.FigNodeModelElement;
 75  
 import org.tigris.gef.base.Editor;
 76  
 import org.tigris.gef.base.Geometry;
 77  
 import org.tigris.gef.base.Globals;
 78  
 import org.tigris.gef.base.LayerPerspective;
 79  
 import org.tigris.gef.presentation.Fig;
 80  
 import org.tigris.gef.presentation.FigPoly;
 81  
 import org.tigris.gef.presentation.FigRect;
 82  
 import org.tigris.gef.presentation.FigText;
 83  
 
 84  
 /**
 85  
  * Class to display graphics for a UML package in a class diagram,
 86  
  * consisting of a "tab" and a "body". <p>
 87  
  * 
 88  
  * The tab of the Package Fig is build of 2 pieces: 
 89  
  * the stereotypes at the top, and the name below it. <p>
 90  
  * 
 91  
  * The name box covers the whole tab, i.e. its size
 92  
  * is always equal to the total size of the tab. 
 93  
  * It is not transparent, and has a line border. 
 94  
  * Its text sits at the bottom of the fig, to leave room for stereotypes. <p>
 95  
  * 
 96  
  * The stereotype fig is transparent, and sits at the top
 97  
  * inside the name fig. It is drawn on top of the name fig box. <p>
 98  
  * 
 99  
  * The tab of the Package Fig can only be resized by the user horizontally.
 100  
  * The body can be resized horizontally and vertically by the user. <p>
 101  
  * 
 102  
  * Double clicking on the body has a special consequence: 
 103  
  * the user is asked if he wants to create a new class diagram
 104  
  * for this package. <p>
 105  
  * 
 106  
  * ArgoUML does not support the option of showing the name 
 107  
  * of the package in the body, 
 108  
  * as described in the UML standard (chapter Notation - Package). <p>
 109  
  * 
 110  
  * Neither does ArgoUML currently support showing properties in the tab, 
 111  
  * see issue 1214. <p>
 112  
  * 
 113  
  * In front of the name, ArgoUML may optionally show the visibility.
 114  
  */
 115  0
 public class FigPackage extends FigNodeModelElement
 116  
     implements StereotypeContainer, VisibilityContainer {
 117  
 
 118  0
     private static final Logger LOG = Logger.getLogger(FigPackage.class);
 119  
 
 120  
     /** The minimal height of the name. */
 121  
     private static final int MIN_HEIGHT = 21;
 122  
     /** The minimal width of the name. */
 123  
     private static final int MIN_WIDTH = 50;
 124  
 
 125  
     /** The initial width of the outer box. */
 126  0
     private int width = 140;
 127  
     /** The initial height of the outer box. */
 128  0
     private int height = 100;
 129  
     
 130  
     /** The width of the cut out area at the right top corner. */
 131  0
     private int indentX = 50;
 132  
 
 133  0
     private int textH = 20;
 134  
 
 135  
     /**
 136  
      * The total height of the tab.
 137  
      */
 138  0
     private int tabHeight = 20;
 139  
 
 140  
     private FigPackageFigText body;
 141  
     private PackageBackground background;
 142  
     
 143  
     private FigPoly figPoly;
 144  
 
 145  
     /**
 146  
      * Flag that indicates if the user wants any stereotype to be shown. 
 147  
      * It corresponds to the check-mark on the Presentation tab.
 148  
      * There is no relation with the actual presence of any stereotypes.
 149  
      * This setting has Fig-scope, hence it is saved with the Fig layout data.
 150  
      */
 151  0
     private boolean stereotypeVisible = true;
 152  
 
 153  
     @Override
 154  
     protected Fig createBigPortFig() {
 155  0
         PackagePortFigRect ppfr = 
 156  
             new PackagePortFigRect(0, 0, width, height, indentX, tabHeight);
 157  0
         ppfr.setFilled(false);
 158  0
         ppfr.setLineWidth(0);
 159  0
         return ppfr;
 160  
     }
 161  
 
 162  
     private void initialize() {
 163  0
         body.setEditable(false);
 164  
 
 165  0
         background = new PackageBackground(0, 0, width, height, indentX, tabHeight);
 166  
         
 167  0
         getNameFig().setBounds(0, 0, width - indentX, textH + 2);
 168  0
         getNameFig().setJustification(FigText.JUSTIFY_LEFT);
 169  
 
 170  
         // Set properties of the stereotype box. 
 171  
         // Initially not set to be displayed, but this will be changed
 172  
         // when we try to render it, if we find we have a stereotype.
 173  
 
 174  0
         getStereotypeFig().setVisible(false);
 175  
 
 176  
         // add Figs to the FigNode in back-to-front order
 177  0
         addFig(getBigPort());
 178  0
         addFig(background);
 179  0
         addFig(getNameFig());
 180  0
         addFig(getStereotypeFig());
 181  0
         addFig(body);
 182  
 
 183  0
         setBlinkPorts(false); //make port invisible unless mouse enters
 184  
 
 185  
         // Make all the parts match the main fig
 186  0
         setFilled(true);
 187  0
         setFillColor(FILL_COLOR);
 188  0
         setLineColor(LINE_COLOR);
 189  0
         setLineWidth(LINE_WIDTH);
 190  
 
 191  0
         updateEdges();
 192  0
     }
 193  
 
 194  
     /**
 195  
      * Construct a package figure with the given owner, bounds, and rendering
 196  
      * settings. This constructor is used by the PGML parser.
 197  
      * 
 198  
      * @param owner owning model element
 199  
      * @param bounds position and size or null if fig hasn't been placed
 200  
      * @param settings rendering settings
 201  
      */
 202  
     public FigPackage(Object owner, Rectangle bounds, 
 203  
             DiagramSettings settings) {
 204  0
         super(owner, bounds, settings);
 205  
 
 206  
         // Create a Body that reacts to double-clicks and jumps to a diagram.
 207  0
         body = new FigPackageFigText(getOwner(), 
 208  
                 new Rectangle(0, textH, width, height - textH), getSettings());
 209  
         
 210  0
         initialize();
 211  
         
 212  0
         if (bounds != null) {
 213  0
             setLocation(bounds.x, bounds.y);
 214  
         }
 215  0
         setBounds(getBounds());
 216  0
     }
 217  
 
 218  
     /*
 219  
      * @see java.lang.Object#clone()
 220  
      */
 221  
     @Override
 222  
     public Object clone() {
 223  0
         FigPackage figClone = (FigPackage) super.clone();
 224  0
         for (Fig thisFig : (List<Fig>) getFigs()) {
 225  0
             if (thisFig == body) {
 226  0
                 figClone.body = (FigPackageFigText) thisFig;
 227  
             }
 228  
         }
 229  0
         return figClone;
 230  
     }
 231  
 
 232  
     /**
 233  
      * @return Returns the fig for the symbol.
 234  
      */
 235  
     protected FigPoly getFigPoly() {
 236  0
         return figPoly;
 237  
     }
 238  
 
 239  
     /**
 240  
      * @param figPoly The fig for the symbol to set.
 241  
      */
 242  
     protected void setFigPoly(FigPoly figPoly) {
 243  0
         this.figPoly = figPoly;
 244  0
     }
 245  
 
 246  
     /*
 247  
      * @see org.tigris.gef.presentation.Fig#setLineColor(java.awt.Color)
 248  
      */
 249  
     @Override
 250  
     public void setLineColor(Color col) {
 251  0
         super.setLineColor(col);
 252  0
         getStereotypeFig().setLineColor(null);
 253  0
         getNameFig().setLineColor(col);
 254  0
         body.setLineColor(col);
 255  0
         if (figPoly != null) {
 256  0
             figPoly.setLineColor(col);
 257  
         }
 258  0
     }
 259  
 
 260  
     /*
 261  
      * @see org.tigris.gef.presentation.Fig#getLineColor()
 262  
      */
 263  
     @Override
 264  
     public Color getLineColor() {
 265  0
         return body.getLineColor();
 266  
     }
 267  
 
 268  
     /*
 269  
      * @see org.tigris.gef.presentation.Fig#getFillColor()
 270  
      */
 271  
     @Override
 272  
     public Color getFillColor() {
 273  0
         return background.getFillColor();
 274  
     }
 275  
 
 276  
     @Override
 277  
     public boolean isFilled() {
 278  0
         return background.isFilled();
 279  
     }
 280  
 
 281  
     /*
 282  
      * @see org.tigris.gef.presentation.Fig#setLineWidth(int)
 283  
      */
 284  
     @Override
 285  
     public void setLineWidth(int w) {
 286  
         // There are 2 boxes showing lines: the tab and the body.
 287  0
         getNameFig().setLineWidth(w);
 288  0
         body.setLineWidth(w);
 289  0
     }
 290  
 
 291  
     /*
 292  
      * @see org.tigris.gef.presentation.Fig#getLineWidth()
 293  
      */
 294  
     @Override
 295  
     public int getLineWidth() {
 296  0
         return body.getLineWidth();
 297  
     }
 298  
 
 299  
     /*
 300  
      * @see org.argouml.uml.diagram.ui.FigNodeModelElement#updateStereotypeText()
 301  
      */
 302  
     @Override
 303  
     protected void updateStereotypeText() {
 304  0
         Object modelElement = getOwner();
 305  
 
 306  0
         if (modelElement == null) {
 307  0
             return;
 308  
         }
 309  
 
 310  0
         Rectangle rect = getBounds();
 311  
 
 312  
         /* check if any stereotype is defined */
 313  0
         if (Model.getFacade().getStereotypes(modelElement).isEmpty()) {
 314  0
             if (getStereotypeFig().isVisible()) {
 315  0
                 getNameFig().setTopMargin(0);
 316  0
                 getStereotypeFig().setVisible(false);
 317  
             } // else nothing changed
 318  
         } else {
 319  
             /* we got at least one stereotype */
 320  
             /* This populates the stereotypes area: */
 321  0
             super.updateStereotypeText();
 322  0
             if (!isStereotypeVisible()) {
 323  
                 // the user wants to hide them
 324  0
                 getNameFig().setTopMargin(0);
 325  0
                 getStereotypeFig().setVisible(false);
 326  0
             } else if (!getStereotypeFig().isVisible()) {
 327  0
                 getNameFig().setTopMargin(
 328  
                         getStereotypeFig().getMinimumSize().height);
 329  0
                 getStereotypeFig().setVisible(true);
 330  
             } // else nothing changed
 331  
         }
 332  
 
 333  0
         forceRepaintShadow();
 334  0
         setBounds(rect.x, rect.y, rect.width, rect.height);
 335  0
     }
 336  
     
 337  
     /**
 338  
      * Override ancestor behaviour by always calling setBounds even if the
 339  
      * size hasn't changed. Without this override the Package bounds draw
 340  
      * incorrectly. This is not the best fix but is a workaround until the
 341  
      * true cause is known. See issue 6135.
 342  
      * 
 343  
      * @see org.argouml.uml.diagram.ui.FigNodeModelElement#updateBounds()
 344  
      */
 345  
     protected void updateBounds() {
 346  0
         if (!isCheckSize()) {
 347  0
             return;
 348  
         }
 349  0
         Rectangle bbox = getBounds();
 350  0
         Dimension minSize = getMinimumSize();
 351  0
         bbox.width = Math.max(bbox.width, minSize.width);
 352  0
         bbox.height = Math.max(bbox.height, minSize.height);
 353  0
         setBounds(bbox.x, bbox.y, bbox.width, bbox.height);
 354  0
     }    
 355  
 
 356  
     /**
 357  
      * USED BY PGML.tee.
 358  
      * @return the class name and bounds together with compartment
 359  
      * visibility.
 360  
      */
 361  
     @Override
 362  
     public String classNameAndBounds() {
 363  0
         return super.classNameAndBounds()
 364  
                 + "stereotypeVisible=" + isStereotypeVisible()
 365  
                 + ";"
 366  
                 + "visibilityVisible=" + isVisibilityVisible();
 367  
     }
 368  
 
 369  
 
 370  
     /*
 371  
      * @see org.tigris.gef.presentation.Fig#getUseTrapRect()
 372  
      */
 373  
     @Override
 374  
     public boolean getUseTrapRect() {
 375  0
         return true;
 376  
     }
 377  
 
 378  
     /*
 379  
      * @see org.tigris.gef.presentation.Fig#getMinimumSize()
 380  
      */
 381  
     @Override
 382  
     public Dimension getMinimumSize() {
 383  
         // Use "aSize" to build up the minimum size. Start with the size of the
 384  
         // name fig and build up.
 385  0
         Dimension aSize = new Dimension(getNameFig().getMinimumSize());
 386  
 
 387  0
         if (figPoly != null) {
 388  
             /* The figPoly is located at the right of the name text. 
 389  
              * The nameFig size is increased, so that it fits its text, 
 390  
              * and the figPoly next to the text, all within the boundaries 
 391  
              * of the nameFig. */
 392  0
             Dimension symbol = figPoly.getSize();
 393  0
             aSize.width += symbol.width;
 394  0
             aSize.height = Math.max(aSize.height, symbol.height);
 395  
         }
 396  
         
 397  0
         aSize.height = Math.max(aSize.height, MIN_HEIGHT);
 398  0
         aSize.width = Math.max(aSize.width, MIN_WIDTH);
 399  
 
 400  
         // If we have any number of stereotypes displayed, then allow 
 401  
         // some space for that (only width, height is included in nameFig):
 402  0
         if (isStereotypeVisible()) {
 403  0
             Dimension st = getStereotypeFig().getMinimumSize();
 404  0
             aSize.width =
 405  
                 Math.max(aSize.width, st.width);
 406  
         }
 407  
 
 408  
         // take into account the tab is not as wide as the body:
 409  0
         aSize.width += indentX + 1; 
 410  
 
 411  
         // we want at least some of the package body to be displayed
 412  0
         aSize.height += 28 + 2 * getLineWidth();
 413  
 
 414  
         // And now aSize has the answer
 415  0
         return aSize;
 416  
     }
 417  
 
 418  
     /**
 419  
      * Sets the bounds, but the size will be at least the one returned by
 420  
      * {@link #getMinimumSize()}.<p>
 421  
      *
 422  
      * If the required height is bigger, then the additional height is
 423  
      * not distributed among all figs (i.e. compartments), 
 424  
      * but goes into the body. Hence, the
 425  
      * accumulated height of all visible figs equals the demanded height<p>.
 426  
      *
 427  
      * Some of this has "magic numbers" hardcoded in. In particular there is
 428  
      * a knowledge that the minimum height of a name compartment is 21
 429  
      * pixels. This height is needed to be able to display the "Clarifier"
 430  
      * inside the name compartment.
 431  
      *
 432  
      * @param xa  Desired X coordinate of upper left corner
 433  
      *
 434  
      * @param ya  Desired Y coordinate of upper left corner
 435  
      *
 436  
      * @param w  Desired width of the FigClass
 437  
      *
 438  
      * @param h  Desired height of the FigClass
 439  
      */
 440  
     @Override
 441  
     protected void setStandardBounds(int xa, int ya, int w, int h) {
 442  
         // Save our old boundaries (needed later), and get minimum size
 443  
         // info. "aSize" will be used to maintain a running calculation of our
 444  
         // size at various points.
 445  
 
 446  0
         Rectangle oldBounds = getBounds();
 447  
 
 448  
         // The new size can not be smaller than the minimum.
 449  0
         Dimension minimumSize = getMinimumSize();
 450  0
         int newW = Math.max(w, minimumSize.width);
 451  0
         int newH = Math.max(h, minimumSize.height);
 452  
 
 453  
         // Now resize all sub-figs, including not displayed figs. Start by the
 454  
         // name. We override the getMinimumSize if it is less than our view (21
 455  
         // pixels hardcoded!). Add in the shared extra, plus in this case the
 456  
         // correction.
 457  
 
 458  0
         Dimension nameMin = getNameFig().getMinimumSize();
 459  0
         int minNameHeight = Math.max(nameMin.height, MIN_HEIGHT);
 460  
 
 461  
         // Now sort out the stereotype display. If the stereotype is displayed,
 462  
         // move the upper boundary of the name compartment up and set new
 463  
         // bounds for the name and the stereotype compartments and the
 464  
         // stereoLineBlinder that blanks out the line between the two
 465  
 
 466  0
         int currentY = ya;
 467  
 
 468  0
         int tabWidth = newW - indentX;
 469  
 
 470  0
         if (isStereotypeVisible()) {
 471  0
             Dimension stereoMin = getStereotypeFig().getMinimumSize();
 472  0
             getNameFig().setTopMargin(stereoMin.height);
 473  0
             getNameFig().setBounds(xa, currentY, tabWidth + 1, minNameHeight);
 474  
 
 475  0
             getStereotypeFig().setBounds(xa, ya,
 476  
                 tabWidth, stereoMin.height + 1);
 477  
 
 478  0
             if (tabWidth < stereoMin.width + 1) {
 479  0
                 tabWidth = stereoMin.width + 2;
 480  
             }
 481  0
         } else {
 482  0
             getNameFig().setBounds(xa, currentY, tabWidth + 1, minNameHeight);
 483  
         }
 484  
         
 485  
         // Advance currentY to where the start of the body box is,
 486  
         // remembering that it overlaps the next box by 1 pixel. Calculate the
 487  
         // size of the body box, and update the Y pointer past it if it is
 488  
         // displayed.
 489  
 
 490  0
         currentY += minNameHeight - 1; // -1 for 1 pixel overlap
 491  0
         body.setBounds(xa, currentY, newW, newH + ya - currentY);
 492  
 
 493  0
         tabHeight = currentY - ya;
 494  
         // set bounds of big box
 495  
 
 496  0
         getBigPort().setBounds(xa, ya, newW, newH);
 497  
 
 498  0
         if (figPoly != null) {
 499  
             /* The figPoly is located at the right edge of the nameFig. 
 500  
              * The nameFig size is such that it at least fits its text, 
 501  
              * and the figPoly next to the text. 
 502  
              * Making the package bigger, causes the figPoly to stick to 
 503  
              * the right edge.*/
 504  0
             Rectangle previousBounds = figPoly.getBounds();
 505  0
             Rectangle name = getNameFig().getBounds();
 506  0
             int nx = name.x + name.width - figPoly.getWidth()
 507  
                 - getLineWidth() - getNameFig().getRightMargin();
 508  0
             int ny = name.y + getLineWidth() + getNameFig().getTopMargin();
 509  0
             figPoly.translate((nx - previousBounds.x),
 510  
                     ny - previousBounds.y);
 511  
         }
 512  
 
 513  
         // Now force calculation of the bounds of the figure, update the edges
 514  
         // and trigger anyone who's listening to see if the "bounds" property
 515  
         // has changed.
 516  
         
 517  0
         background.setBounds(xa, ya, w, h);
 518  
 
 519  0
         calcBounds();
 520  0
         updateEdges();
 521  0
         firePropChange("bounds", oldBounds, getBounds());
 522  0
     }
 523  
 
 524  
     /**
 525  
      * Build a collection of menu items relevant for a right-click
 526  
      * popup menu on a Package.
 527  
      *
 528  
      * @param     me     a mouse event
 529  
      * @return          a collection of menu items
 530  
      */
 531  
     @Override
 532  
     public Vector getPopUpActions(MouseEvent me) {
 533  0
         Vector popUpActions = super.getPopUpActions(me);
 534  
 
 535  
         // Modifier ...
 536  0
         popUpActions.add(
 537  
                 popUpActions.size() - getPopupAddOffset(),
 538  
                 buildModifierPopUp(ABSTRACT | LEAF | ROOT));
 539  
 
 540  
         // Visibility ...
 541  0
         popUpActions.add(
 542  
                 popUpActions.size() - getPopupAddOffset(),
 543  
                 buildVisibilityPopUp());
 544  
 
 545  0
         return popUpActions;
 546  
     }
 547  
 
 548  
     @Override
 549  
     protected ArgoJMenu buildShowPopUp() {
 550  0
         ArgoJMenu showMenu = super.buildShowPopUp();
 551  
         /* Only show the menuitems if they make sense: */
 552  0
         Editor ce = Globals.curEditor();
 553  0
         List<Fig> figs = ce.getSelectionManager().getFigs();
 554  0
         boolean sOn = false;
 555  0
         boolean sOff = false;
 556  0
         boolean vOn = false;
 557  0
         boolean vOff = false;
 558  0
         for (Fig f : figs) {
 559  0
             if (f instanceof StereotypeContainer) {
 560  0
                 boolean v = ((StereotypeContainer) f).isStereotypeVisible();
 561  0
                 if (v) {
 562  0
                     sOn = true;
 563  
                 } else {
 564  0
                     sOff = true;
 565  
                 }
 566  0
                 v = ((VisibilityContainer) f).isVisibilityVisible();
 567  0
                 if (v) {
 568  0
                     vOn = true;
 569  
                 } else {
 570  0
                     vOff = true;
 571  
                 }
 572  0
             }
 573  
         }
 574  
 
 575  0
         if (sOn) {
 576  0
             showMenu.add(new HideStereotypeAction());
 577  
         }
 578  
 
 579  0
         if (sOff) {
 580  0
             showMenu.add(new ShowStereotypeAction());
 581  
         }
 582  
 
 583  0
         if (vOn) {
 584  0
             showMenu.add(new HideVisibilityAction());
 585  
         }
 586  
 
 587  0
         if (vOff) {
 588  0
             showMenu.add(new ShowVisibilityAction());
 589  
         }
 590  
 
 591  0
         return showMenu;
 592  
     }
 593  
 
 594  
     /**
 595  
      * Change the visibility of the stereotypes of all Figs.
 596  
      *
 597  
      * @param value true if it needs to become visible
 598  
      */
 599  
     private void doStereotype(boolean value) {
 600  0
         Editor ce = Globals.curEditor();
 601  0
         List<Fig> figs = ce.getSelectionManager().getFigs();
 602  0
         for (Fig f : figs) {
 603  0
             if (f instanceof StereotypeContainer) {
 604  0
                 ((StereotypeContainer) f).setStereotypeVisible(value);
 605  
             }
 606  0
             if (f instanceof FigNodeModelElement) {
 607  0
                 ((FigNodeModelElement) f).forceRepaintShadow();
 608  0
                 ((ArgoFig) f).renderingChanged();
 609  
             }
 610  0
             f.damage();
 611  
         }
 612  0
     }
 613  
 
 614  
     /**
 615  
      * Change the visibility of the Visibility of all Figs.
 616  
      *
 617  
      * @param value true if it needs to become visible
 618  
      */
 619  
     private void doVisibility(boolean value) {
 620  0
         Editor ce = Globals.curEditor();
 621  0
         List<Fig> figs = ce.getSelectionManager().getFigs();
 622  0
         for (Fig f : figs) {
 623  0
             if (f instanceof VisibilityContainer) {
 624  0
                 ((VisibilityContainer) f).setVisibilityVisible(value);
 625  
             }
 626  0
             f.damage();
 627  
         }
 628  0
     }
 629  
 
 630  
     /**
 631  
      * A text fig for the body of a a Package 
 632  
      * which does not contain any text, 
 633  
      * but solely exists to trigger a jump to a diagram for
 634  
      * the named package when double clicked.
 635  
      */
 636  
     class FigPackageFigText extends ArgoFigText {
 637  
         
 638  
         /**
 639  
          * Construct a text fig for a Package which will jump to diagram for
 640  
          * the named package when double clicked.
 641  
          * 
 642  
          * @param owner owning UML element
 643  
          * @param bounds position and size
 644  
          * @param settings render settings
 645  
          */
 646  
         public FigPackageFigText(Object owner, Rectangle bounds, 
 647  0
                 DiagramSettings settings) {
 648  0
             super(owner, bounds, settings, false);
 649  0
         }
 650  
         
 651  
         /**
 652  
          * TODO: mvw: Would it not be better if this code 
 653  
          * would go in startTextEditor(), not overruling mouseClicked(). 
 654  
          * But we made this fig not editable, 
 655  
          * to stop it from reacting on key-presses.
 656  
          * Anyhow - this is a hack - abusing a FigText - GEF does 
 657  
          * not really support double-clicking on a Fig to trigger some action.
 658  
          */
 659  
         @Override
 660  
         public void mouseClicked(MouseEvent me) {
 661  
 
 662  0
             String lsDefaultName = "main";
 663  
 
 664  
             // TODO: This code appears to be designed to jump to the diagram
 665  
             // containing the contents of the package that was double clicked
 666  
             // but it looks like it's always searching for the name "main"
 667  
             // instead of the package name.
 668  
             // TODO: But in any case, it should be delegating this work to 
 669  
             // to something that knows about the diagrams and they contents -tfm
 670  0
             if (me.getClickCount() >= 2) {
 671  0
                 Object lPkg = FigPackage.this.getOwner();
 672  0
                 if (lPkg != null) {
 673  0
                     Object lNS = lPkg;
 674  
 
 675  0
                     Project lP = getProject();
 676  
 
 677  0
                     List<ArgoDiagram> diags = lP.getDiagramList();
 678  0
                     ArgoDiagram lFirst = null;
 679  0
                     for (ArgoDiagram lDiagram : diags) {
 680  0
                         Object lDiagramNS = lDiagram.getNamespace();
 681  0
                         if ((lNS == null && lDiagramNS == null)
 682  
                             || (lNS.equals(lDiagramNS))) {
 683  
                             /* save first */
 684  0
                             if (lFirst == null) {
 685  0
                                 lFirst = lDiagram;
 686  
                             }
 687  
 
 688  0
                             if (lDiagram.getName() != null
 689  
                                 && lDiagram.getName().startsWith(
 690  
                                         lsDefaultName)) {
 691  0
                                 me.consume();
 692  0
                                 super.mouseClicked(me);
 693  0
                                 TargetManager.getInstance().setTarget(lDiagram);
 694  0
                                 return;
 695  
                             }
 696  
                         }
 697  0
                     } /*while*/
 698  
 
 699  
                     /* If we get here then we didn't get the
 700  
                      * default diagram.
 701  
                      */
 702  0
                     if (lFirst != null) {
 703  0
                         me.consume();
 704  0
                         super.mouseClicked(me);
 705  
 
 706  0
                         TargetManager.getInstance().setTarget(lFirst);
 707  0
                         return;
 708  
                     }
 709  
 
 710  
                     /* Try to create a new class diagram.
 711  
                      */
 712  0
                     me.consume();
 713  0
                     super.mouseClicked(me);
 714  
                     try {
 715  0
                         createClassDiagram(lNS, lsDefaultName, lP);
 716  0
                     } catch (Exception ex) {
 717  0
                         LOG.error(ex);
 718  0
                     }
 719  
 
 720  0
                     return;
 721  
 
 722  
                 } /*if package */
 723  
             } /* if doubleclicks */
 724  0
             super.mouseClicked(me);
 725  0
         }
 726  
         
 727  
         public void setFilled(boolean f) {
 728  0
             super.setFilled(false);
 729  0
         }
 730  
         
 731  
         public void setFillColor(Color c) {
 732  0
             super.setFillColor(c);
 733  0
         }
 734  
 
 735  
         /**
 736  
          * The UID.
 737  
          */
 738  
         private static final long serialVersionUID = -1355316218065323634L;
 739  
     }
 740  
 
 741  
     private void createClassDiagram(
 742  
             Object namespace,
 743  
             String defaultName,
 744  
             Project project) throws PropertyVetoException {
 745  
 
 746  
         String namespaceDescr;
 747  0
         if (namespace != null
 748  
                 && Model.getFacade().getName(namespace) != null) {
 749  0
             namespaceDescr = Model.getFacade().getName(namespace);
 750  
         } else {
 751  0
             namespaceDescr = Translator.localize("misc.name.anon");
 752  
         }
 753  
 
 754  0
         String dialogText = "Add new class diagram to " + namespaceDescr + "?";
 755  0
         int option =
 756  
             JOptionPane.showConfirmDialog(
 757  
                 null,
 758  
                 dialogText,
 759  
                 "Add new class diagram?",
 760  
                 JOptionPane.YES_NO_OPTION);
 761  
 
 762  0
         if (option == JOptionPane.YES_OPTION) {
 763  
 
 764  0
             ArgoDiagram classDiagram =
 765  
                 DiagramFactory.getInstance().
 766  
                     createDiagram(DiagramType.Class, namespace, null);
 767  
 
 768  0
             String diagramName = defaultName + "_" + classDiagram.getName();
 769  
 
 770  0
             project.addMember(classDiagram);
 771  
 
 772  0
             TargetManager.getInstance().setTarget(classDiagram);
 773  
             /* change prefix */
 774  0
             classDiagram.setName(diagramName);
 775  0
             ExplorerEventAdaptor.getInstance().structureChanged();
 776  
         }
 777  0
     }
 778  
 
 779  
     /*
 780  
      * @see org.argouml.uml.diagram.ui.StereotypeContainer#isStereotypeVisible()
 781  
      */
 782  
     public boolean isStereotypeVisible() {
 783  0
         return stereotypeVisible;
 784  
     }
 785  
 
 786  
     /*
 787  
      * @see org.argouml.uml.diagram.ui.StereotypeContainer#setStereotypeVisible(boolean)
 788  
      */
 789  
     public void setStereotypeVisible(boolean isVisible) {
 790  0
         stereotypeVisible = isVisible;
 791  0
         renderingChanged();
 792  0
         damage();
 793  0
     }
 794  
 
 795  
     /*
 796  
      * @see org.argouml.uml.diagram.ui.VisibilityContainer#isVisibilityVisible()
 797  
      */
 798  
     public boolean isVisibilityVisible() {
 799  0
         return getNotationSettings().isShowVisibilities();
 800  
     }
 801  
 
 802  
     /*
 803  
      * @see org.argouml.uml.diagram.ui.VisibilityContainer#setVisibilityVisible(boolean)
 804  
      */
 805  
     public void setVisibilityVisible(boolean isVisible) {
 806  0
         getNotationSettings().setShowVisibilities(isVisible);
 807  0
         renderingChanged();
 808  0
         damage();
 809  0
     }
 810  
 
 811  
     /*
 812  
      * @see org.argouml.uml.diagram.ui.FigNodeModelElement#textEditStarted(org.tigris.gef.presentation.FigText)
 813  
      */
 814  
     @Override
 815  
     protected void textEditStarted(FigText ft) {
 816  
 
 817  0
         if (ft == getNameFig()) {
 818  0
             showHelp("parsing.help.fig-package");
 819  
         }
 820  0
     }
 821  
 
 822  
     /*
 823  
      * @see org.tigris.gef.presentation.Fig#getClosestPoint(java.awt.Point)
 824  
      */
 825  
     @Override
 826  
     public Point getClosestPoint(Point anotherPt) {
 827  0
         Rectangle r = getBounds();
 828  0
         int[] xs = {
 829  
             r.x, r.x + r.width - indentX, r.x + r.width - indentX,
 830  
             r.x + r.width,   r.x + r.width,  r.x,            r.x,
 831  
         };
 832  0
         int[] ys = {
 833  
             r.y, r.y,                     r.y + tabHeight,
 834  
             r.y + tabHeight, r.y + r.height, r.y + r.height, r.y,
 835  
         };
 836  0
         Point p =
 837  
             Geometry.ptClosestTo(
 838  
                 xs,
 839  
                 ys,
 840  
                 7,
 841  
                 anotherPt);
 842  0
         return p;
 843  
     }
 844  
     
 845  
     @Override
 846  
     protected void modelChanged(PropertyChangeEvent mee) {
 847  
         
 848  0
         if (mee instanceof RemoveAssociationEvent
 849  
                 && "ownedElement".equals(mee.getPropertyName())
 850  
                 && mee.getSource() == getOwner()) {
 851  
             // A model element has been removed from this packages namespace
 852  
             // If the Fig representing that model element is on the same
 853  
             // diagram as this package then make sure it is not enclosed by
 854  
             // this package.
 855  
             // TODO: In my view the Fig representing the model element should be
 856  
             // removed from the diagram. Yet to be agreed. Bob.
 857  0
             if (LOG.isInfoEnabled() && mee.getNewValue() == null) {
 858  0
                 LOG.info(Model.getFacade().getName(mee.getOldValue())
 859  
                         + " has been removed from the namespace of "
 860  
                         + Model.getFacade().getName(getOwner())
 861  
                         + " by notice of " + mee.toString());
 862  
             }
 863  0
             LayerPerspective layer = (LayerPerspective) getLayer();
 864  0
             Fig f = layer.presentationFor(mee.getOldValue());
 865  0
             if (f != null && f.getEnclosingFig() == this) {
 866  0
                 removeEnclosedFig(f);
 867  0
                 f.setEnclosingFig(null);
 868  
             }
 869  
         }
 870  0
         super.modelChanged(mee);
 871  0
     }
 872  
 
 873  
     /**
 874  
      * The UID.
 875  
      */
 876  
     private static final long serialVersionUID = 3617092272529451041L;
 877  
 
 878  
     private class HideStereotypeAction extends UndoableAction {
 879  
         /**
 880  
          * The key for the action name.
 881  
          */
 882  
         private static final String ACTION_KEY =
 883  
             "menu.popup.show.hide-stereotype";
 884  
 
 885  
         /**
 886  
          * Constructor.
 887  
          */
 888  0
         HideStereotypeAction() {
 889  0
             super(Translator.localize(ACTION_KEY),
 890  
                     ResourceLoaderWrapper.lookupIcon(ACTION_KEY));
 891  0
         }
 892  
         /*
 893  
          * @see java.awt.event.ActionListener#actionPerformed(
 894  
          *         java.awt.event.ActionEvent)
 895  
          */
 896  
         @Override
 897  
         public void actionPerformed(ActionEvent ae) {
 898  0
             super.actionPerformed(ae);
 899  0
             doStereotype(false);
 900  0
         }
 901  
 
 902  
         /**
 903  
          * The UID.
 904  
          */
 905  
         private static final long serialVersionUID =
 906  
             1999499813643610674L;
 907  
     }
 908  
 
 909  
     private class ShowStereotypeAction extends UndoableAction {
 910  
         /**
 911  
          * The key for the action name.
 912  
          */
 913  
         private static final String ACTION_KEY =
 914  
             "menu.popup.show.show-stereotype";
 915  
 
 916  
         /**
 917  
          * Constructor.
 918  
          */
 919  0
         ShowStereotypeAction() {
 920  0
             super(Translator.localize(ACTION_KEY),
 921  
                     ResourceLoaderWrapper.lookupIcon(ACTION_KEY));
 922  0
         }
 923  
         /*
 924  
          * @see java.awt.event.ActionListener#actionPerformed(
 925  
          *         java.awt.event.ActionEvent)
 926  
          */
 927  
         @Override
 928  
         public void actionPerformed(ActionEvent ae) {
 929  0
             super.actionPerformed(ae);
 930  0
             doStereotype(true);
 931  0
         }
 932  
 
 933  
         /**
 934  
          * The UID.
 935  
          */
 936  
         private static final long serialVersionUID =
 937  
             -4327161642276705610L;
 938  
     }
 939  
 
 940  
     private class HideVisibilityAction extends UndoableAction {
 941  
         /**
 942  
          * The key for the action name.
 943  
          */
 944  
         private static final String ACTION_KEY =
 945  
             "menu.popup.show.hide-visibility";
 946  
 
 947  
         /**
 948  
          * Constructor.
 949  
          */
 950  0
         HideVisibilityAction() {
 951  0
             super(Translator.localize(ACTION_KEY),
 952  
                     ResourceLoaderWrapper.lookupIcon(ACTION_KEY));
 953  0
         }
 954  
         /*
 955  
          * @see java.awt.event.ActionListener#actionPerformed(
 956  
          *         java.awt.event.ActionEvent)
 957  
          */
 958  
         @Override
 959  
         public void actionPerformed(ActionEvent ae) {
 960  0
             super.actionPerformed(ae);
 961  0
             doVisibility(false);
 962  0
         }
 963  
 
 964  
         /**
 965  
          * The UID.
 966  
          */
 967  
         private static final long serialVersionUID =
 968  
             8574809709777267866L;
 969  
     }
 970  
 
 971  
     private class ShowVisibilityAction extends UndoableAction {
 972  
         /**
 973  
          * The key for the action name.
 974  
          */
 975  
         private static final String ACTION_KEY =
 976  
             "menu.popup.show.show-visibility";
 977  
 
 978  
         /**
 979  
          * Constructor.
 980  
          */
 981  0
         ShowVisibilityAction() {
 982  0
             super(Translator.localize(ACTION_KEY),
 983  
                     ResourceLoaderWrapper.lookupIcon(ACTION_KEY));
 984  0
         }
 985  
         /*
 986  
          * @see java.awt.event.ActionListener#actionPerformed(
 987  
          *         java.awt.event.ActionEvent)
 988  
          */
 989  
         @Override
 990  
         public void actionPerformed(ActionEvent ae) {
 991  0
             super.actionPerformed(ae);
 992  0
             doVisibility(true);
 993  0
         }
 994  
 
 995  
         /**
 996  
          * The UID.
 997  
          */
 998  
         private static final long serialVersionUID =
 999  
             7722093402948975834L;
 1000  
     }
 1001  
     
 1002  
     private class PackageBackground extends FigPoly {
 1003  
         
 1004  
         int indentX;
 1005  
         int tabHeight;
 1006  
         
 1007  
         /**
 1008  
          * The constructor.
 1009  
          *
 1010  
          * @param x The x.
 1011  
          * @param y The y.
 1012  
          * @param w The width.
 1013  
          * @param h The height.
 1014  
          * @param ix The indent.
 1015  
          * @param th The tab height.
 1016  
          */
 1017  0
         public PackageBackground(int x, int y, int w, int h, int ix, int th) {
 1018  0
             super(x, y);
 1019  0
             addPoint(x + ix - 1, y);
 1020  0
             addPoint(x + ix - 1, y + th);
 1021  0
             addPoint(x + w - 1, y + th);
 1022  0
             addPoint(x + w - 1, y + h);
 1023  0
             addPoint(x, y + h);
 1024  0
             addPoint(x, y);
 1025  0
             setFilled(true);
 1026  0
             this.indentX = ix;
 1027  0
             tabHeight = 30;
 1028  0
         }
 1029  
         
 1030  
         /*
 1031  
          * @see org.tigris.gef.presentation.Fig#getClosestPoint(java.awt.Point)
 1032  
          */
 1033  
         @Override
 1034  
         public Point getClosestPoint(Point anotherPt) {
 1035  0
             Rectangle r = getBounds();
 1036  0
             int[] xs = {
 1037  
                 r.x, r.x + r.width - indentX, r.x + r.width - indentX,
 1038  
                 r.x + r.width,   r.x + r.width,  r.x,            r.x,
 1039  
             };
 1040  0
             int[] ys = {
 1041  
                 r.y, r.y,                     r.y + tabHeight,
 1042  
                 r.y + tabHeight, r.y + r.height, r.y + r.height, r.y,
 1043  
             };
 1044  0
             Point p =
 1045  
                 Geometry.ptClosestTo(
 1046  
                     xs,
 1047  
                     ys,
 1048  
                     7,
 1049  
                     anotherPt);
 1050  0
             return p;
 1051  
         };
 1052  
         
 1053  
         public void setBoundsImpl(
 1054  
                 final int x, 
 1055  
                 final int y, 
 1056  
                 final int w, 
 1057  
                 final int h) {
 1058  
             
 1059  0
             final int labelWidth = getNameBounds().width;
 1060  0
             final int labelHeight = getNameBounds().height;
 1061  
             
 1062  0
             final int xs[] = new int[7];
 1063  0
             final int ys[] = new int[7];
 1064  0
             xs[0] = x;
 1065  0
             ys[0] = y;
 1066  
             
 1067  0
             xs[1] = x + labelWidth - 1;
 1068  0
             ys[1] = y;
 1069  
             
 1070  0
             xs[2] = x + labelWidth - 1;
 1071  0
             ys[2] = y + labelHeight - 1;
 1072  
             
 1073  0
             xs[3] = x + w - 1;
 1074  0
             ys[3] = y + labelHeight - 1;
 1075  
             
 1076  0
             xs[4] = x + w - 1;
 1077  0
             ys[4] = y + h - 1;
 1078  
             
 1079  0
             xs[5] = x;
 1080  0
             ys[5] = y + h - 1;
 1081  
             
 1082  0
             xs[6] = x;
 1083  0
             ys[6] = y;
 1084  
             
 1085  0
             Polygon p = new Polygon(xs, ys, 7);
 1086  
             
 1087  0
             super.setPolygon(p);
 1088  0
             setFilled(true);
 1089  0
             setLineWidth(0);
 1090  0
         }
 1091  
         
 1092  
         public void setLineWidth(int w) {
 1093  0
             super.setLineWidth(0);
 1094  0
         }
 1095  
     }
 1096  
     
 1097  
 } /* end class FigPackage */
 1098  
 
 1099  
 /**
 1100  
  * The bigport needs to overrule the getClosestPoint,
 1101  
  * because it is the port of this FigNode.
 1102  
  *
 1103  
  * @author mvw@tigris.org
 1104  
  */
 1105  
 class PackagePortFigRect extends FigRect {
 1106  
     private int indentX;
 1107  
     private int tabHeight;
 1108  
 
 1109  
     /**
 1110  
      * The constructor.
 1111  
      *
 1112  
      * @param x The x.
 1113  
      * @param y The y.
 1114  
      * @param w The width.
 1115  
      * @param h The height.
 1116  
      * @param ix The indent.
 1117  
      * @param th The tab height.
 1118  
      */
 1119  
     public PackagePortFigRect(int x, int y, int w, int h, int ix, int th) {
 1120  0
         super(x, y, w, h, null, null);
 1121  0
         this.indentX = ix;
 1122  0
         tabHeight = th;
 1123  0
     }
 1124  
 
 1125  
     /*
 1126  
      * @see org.tigris.gef.presentation.Fig#getClosestPoint(java.awt.Point)
 1127  
      */
 1128  
     @Override
 1129  
     public Point getClosestPoint(Point anotherPt) {
 1130  0
         Rectangle r = getBounds();
 1131  0
         int[] xs = {
 1132  
             r.x, r.x + r.width - indentX, r.x + r.width - indentX,
 1133  
             r.x + r.width,   r.x + r.width,  r.x,            r.x,
 1134  
         };
 1135  0
         int[] ys = {
 1136  
             r.y, r.y,                     r.y + tabHeight,
 1137  
             r.y + tabHeight, r.y + r.height, r.y + r.height, r.y,
 1138  
         };
 1139  0
         Point p =
 1140  
             Geometry.ptClosestTo(
 1141  
                 xs,
 1142  
                 ys,
 1143  
                 7,
 1144  
                 anotherPt);
 1145  0
         return p;
 1146  
     }
 1147  
     
 1148  
     public void setFilled(boolean f) {
 1149  0
         super.setFilled(false);
 1150  0
     }
 1151  
     
 1152  
     public void setFillColor(Color c) {
 1153  0
         super.setFillColor(null);
 1154  0
     }
 1155  
 
 1156  
     /**
 1157  
      * The UID.
 1158  
      */
 1159  
     private static final long serialVersionUID = -7083102131363598065L;
 1160  
 }
 1161