Coverage Report - org.argouml.uml.diagram.use_case.ui.FigUseCase
 
Classes in this File Line Coverage Branch Coverage Complexity
FigUseCase
0%
0/102
0%
0/36
1.407
FigUseCase$FigMyCircle
0%
0/12
N/A
1.407
 
 1  
 /* $Id: FigUseCase.java 17923 2010-01-27 05:23:07Z bobtarling $
 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  
 // $Id: FigUseCase.java 17923 2010-01-27 05:23:07Z bobtarling $
 17  
 // Copyright (c) 1996-2009 The Regents of the University of California. All
 18  
 // Rights Reserved. Permission to use, copy, modify, and distribute this
 19  
 // software and its documentation without fee, and without a written
 20  
 // agreement is hereby granted, provided that the above copyright notice
 21  
 // and this paragraph appear in all copies.  This software program and
 22  
 // documentation are copyrighted by The Regents of the University of
 23  
 // California. The software program and documentation are supplied "AS
 24  
 // IS", without any accompanying services from The Regents. The Regents
 25  
 // does not warrant that the operation of the program will be
 26  
 // uninterrupted or error-free. The end-user understands that the program
 27  
 // was developed for research purposes and is advised not to rely
 28  
 // exclusively on the program for any reason.  IN NO EVENT SHALL THE
 29  
 // UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
 30  
 // SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS,
 31  
 // ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
 32  
 // THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
 33  
 // SUCH DAMAGE. THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY
 34  
 // WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 35  
 // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
 36  
 // PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF
 37  
 // CALIFORNIA HAS NO OBLIGATIONS TO PROVIDE MAINTENANCE, SUPPORT,
 38  
 // UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
 39  
 
 40  
 package org.argouml.uml.diagram.use_case.ui;
 41  
 
 42  
 
 43  
 import java.awt.Color;
 44  
 import java.awt.Dimension;
 45  
 import java.awt.Point;
 46  
 import java.awt.Rectangle;
 47  
 import java.awt.event.MouseEvent;
 48  
 import java.util.HashSet;
 49  
 import java.util.Iterator;
 50  
 import java.util.Set;
 51  
 import java.util.Vector;
 52  
 
 53  
 import javax.swing.Action;
 54  
 
 55  
 import org.argouml.model.Model;
 56  
 import org.argouml.ui.ArgoJMenu;
 57  
 import org.argouml.ui.targetmanager.TargetManager;
 58  
 import org.argouml.uml.diagram.DiagramSettings;
 59  
 import org.argouml.uml.diagram.ui.ActionAddExtensionPoint;
 60  
 import org.argouml.uml.diagram.ui.ActionAddNote;
 61  
 import org.argouml.uml.diagram.ui.ActionCompartmentDisplay;
 62  
 import org.argouml.uml.diagram.ui.FigCompartment;
 63  
 import org.argouml.uml.diagram.ui.FigCompartmentBox;
 64  
 import org.argouml.uml.diagram.ui.FigExtensionPointsCompartment;
 65  
 import org.tigris.gef.base.Selection;
 66  
 import org.tigris.gef.presentation.Fig;
 67  
 import org.tigris.gef.presentation.FigCircle;
 68  
 
 69  
 /**
 70  
  * A fig to display use cases on use case diagrams.<p>
 71  
  *
 72  
  * Realized as a solid oval containing the name of the use
 73  
  * case. Optionally may be split into two compartments, with the lower
 74  
  * compartment displaying the extension points for the use case.<p>
 75  
  *
 76  
  * Implements all interfaces through its superclasses.<p>
 77  
  *
 78  
  * There is some coordinate geometry to be done to fit rectangular
 79  
  * text boxes inside an ellipse, and to draw a horizontal line 
 80  
  * at any height within the ellipse, touching the ellipse. 
 81  
  * In the following, we start from a coordinate 
 82  
  * system with the center at the center of the ellipse.
 83  
  * The rectangular text box contains the
 84  
  * name and any extension points if shown, and is deemed to be of
 85  
  * height <em>2h</em> and width <em>2w</em>. We allow a margin of
 86  
  * <em>p</em> above the top and below the bottom of the box, so we
 87  
  * know the height of the ellipse, <em>2b</em> = <em>2h</em> +
 88  
  * <em>2p</em>.<p>
 89  
  *
 90  
  * The formula for an ellipse of width <em>2a</em> and height
 91  
  * <em>2b</em>, centered on the origin, is<p>
 92  
  *
 93  
  * <em>x</em>^2/<em>a</em>^2 + <em>y</em>^2/<em>b</em>^2 = 1.<p>
 94  
  * or:<p>
 95  
  * x²/a² + y²/b² = 1<p>
 96  
  *
 97  
  * We know that a corner of the rectangle is at coordinate
 98  
  * (<em>w</em>,<em>h</em>), since the rectangle must also be centered
 99  
  * on the origin to fit within the ellipse. Substituting these values
 100  
  * for <em>x</em> and <em>y</em> in the formula above, we can compute
 101  
  * <em>a</em>, half the width of the ellipse, since we know
 102  
  * <em>b</em>.<p>
 103  
  *
 104  
  * <em>a</em> = <em>wb</em>/sqrt(<em>b</em>^2 - <em>h</em>^2).<p>
 105  
  *
 106  
  * But <em>b</em> was defined in terms of the height of the rectangle
 107  
  * plus agreed padding at the top, so we can write.<p>
 108  
  *
 109  
  * <em>a</em> = (<em>wh</em> + <em>wb</em>)/
 110  
  *                 sqrt(2<em>hp</em> + <em>p</em>^2)<p>
 111  
  *
 112  
  * Given we now know <em>a</em> and <em>b</em>, we can find the
 113  
  * coordinates of any partition line required between use case name
 114  
  * and extension points.<p>
 115  
  *
 116  
  * Finally we need to transform our coordinates, to recognise that the
 117  
  * origin is at our top left corner, and the Y coordinates are
 118  
  * reversed.<p>
 119  
  */
 120  0
 public class FigUseCase extends FigCompartmentBox {
 121  
 
 122  
     /**
 123  
      * The minimum padding allowed above the rectangle for
 124  
      * the use case name and extension points to the top of the use
 125  
      * case oval itself.
 126  
      */
 127  
     private static final int MIN_VERT_PADDING = 4;
 128  
 
 129  
     /**
 130  
      * The Fig for the extensionPoints compartment (if any).
 131  
      */
 132  
     private FigExtensionPointsCompartment extensionPointsFigCompartment;
 133  
     
 134  
     /**
 135  
      * Initialization which is common to multiple constructors.<p>
 136  
      * 
 137  
      * There should be no size calculations here, nor color setting,
 138  
      * since not all attributes are set yet (like e.g. fill color).
 139  
      */
 140  
     private void initialize(Rectangle bounds) {       
 141  0
         enableSizeChecking(false);
 142  0
         setSuppressCalcBounds(true); 
 143  
         
 144  0
         FigExtensionPointsCompartment epc =
 145  
             /* Side effect: This creates the fig: */
 146  
             getExtensionPointsCompartment();
 147  
 
 148  
         /*
 149  
          * A use case has an external separator.
 150  
          * External means external to the compartment box. 
 151  
          * This horizontal line sticks out of the box, 
 152  
          * and touches the ellipse edge.
 153  
          */
 154  0
         Fig separatorFig = epc.getSeparatorFig();
 155  
         
 156  
         /* TODO: This next line prevent loading a UseCase 
 157  
          * with a stereotype to grow. Why? */
 158  0
         getStereotypeFig().setVisible(true);
 159  
         
 160  
         // add Figs to the FigNode in back-to-front order
 161  0
         addFig(getBigPort());
 162  0
         addFig(getNameFig());
 163  
         // stereotype fig covers the name fig:
 164  0
         addFig(getStereotypeFig());
 165  0
         addFig(epc);
 166  0
         addFig(separatorFig);
 167  
 
 168  
         // Make all the parts match the main fig
 169  0
         setFilled(true);
 170  0
         super.setFillColor(FILL_COLOR);
 171  0
         super.setLineColor(LINE_COLOR);
 172  0
         super.setLineWidth(LINE_WIDTH);
 173  
         
 174  
         // by default, do not show extension points:
 175  0
         setExtensionPointsVisible(false);
 176  
 
 177  
         /* Set the drop location in the case of D&D: */
 178  0
         if (bounds != null) {
 179  0
             setLocation(bounds.x, bounds.y);
 180  
         }
 181  
 
 182  0
         setSuppressCalcBounds(false);
 183  0
         setBounds(getBounds());
 184  0
         enableSizeChecking(true);
 185  0
     }
 186  
     
 187  
     @Override
 188  
     protected Fig createBigPortFig() {
 189  
         /* Use arbitrary dimensions for now. */
 190  0
         Fig b = new FigMyCircle(0, 0, 100, 60);
 191  0
         b.setFilled(true);
 192  0
         b.setFillColor(FILL_COLOR);
 193  0
         b.setLineColor(LINE_COLOR);
 194  0
         b.setLineWidth(LINE_WIDTH);
 195  0
         return b;
 196  
     }
 197  
 
 198  
     /**
 199  
      * Construct a use case figure with the given owner, bounds, and rendering 
 200  
      * settings.  This constructor is used by the PGML parser.
 201  
      * 
 202  
      * @param owner owning model element
 203  
      * @param bounds position and size
 204  
      * @param settings rendering settings
 205  
      */
 206  
     public FigUseCase(Object owner, Rectangle bounds, 
 207  
             DiagramSettings settings) {
 208  0
         super(owner, bounds, settings);
 209  0
         initialize(bounds);
 210  0
     }
 211  
 
 212  
     /**
 213  
      * Build a collection of menu items relevant for a right-click
 214  
      * popup menu on a Use Case.<p>
 215  
      *
 216  
      * Adds to the generic pop up items from the parent.<p>
 217  
      *
 218  
      * @param me  The mouse event that generated this popup.
 219  
      *
 220  
      * @return    A collection of menu items
 221  
      */
 222  
     @Override
 223  
     public Vector getPopUpActions(MouseEvent me) {
 224  
         /* Check if multiple items are selected: */
 225  0
         boolean ms = TargetManager.getInstance().getTargets().size() > 1;
 226  
 
 227  
         // Get the parent vector first
 228  0
         Vector popUpActions = super.getPopUpActions(me);
 229  
 
 230  
         // Add menu to add an extension point or note. Placed one before last,
 231  
         // so the "Properties" entry is always last.
 232  0
         ArgoJMenu addMenu = new ArgoJMenu("menu.popup.add");
 233  
 
 234  0
         if (!ms) {
 235  0
             addMenu.add(ActionAddExtensionPoint.singleton());
 236  
         }
 237  0
         addMenu.add(new ActionAddNote());
 238  
 
 239  0
         popUpActions.add(popUpActions.size() - getPopupAddOffset(), addMenu);
 240  
 
 241  
         // Modifier menu. Placed one before last, so the "Properties" entry is
 242  
         // always last.
 243  0
         popUpActions.add(popUpActions.size() - getPopupAddOffset(),
 244  
                 buildModifierPopUp(LEAF | ROOT));
 245  
 
 246  0
         return popUpActions;
 247  
     }
 248  
 
 249  
     /**
 250  
      * Show menu to display/hide the extension point compartment.
 251  
      * @return the menu
 252  
      * @see org.argouml.uml.diagram.ui.FigNodeModelElement#buildShowPopUp()
 253  
      */
 254  
     @Override
 255  
     protected ArgoJMenu buildShowPopUp() {
 256  0
         ArgoJMenu showMenu = super.buildShowPopUp();
 257  0
         Iterator i = ActionCompartmentDisplay.getActions().iterator();
 258  0
         while (i.hasNext()) {
 259  0
             showMenu.add((Action) i.next());
 260  
         }
 261  0
         return showMenu;
 262  
     }
 263  
 
 264  
     /**
 265  
      * USED BY PGML.tee.
 266  
      * @return the class name and bounds together with compartment
 267  
      * visibility.
 268  
      */
 269  
     @Override
 270  
     public String classNameAndBounds() {
 271  0
         return super.classNameAndBounds()
 272  
                 + "extensionPointVisible=" + isExtensionPointsVisible();
 273  
     }
 274  
 
 275  
     public boolean isExtensionPointsVisible() {
 276  0
         return extensionPointsFigCompartment != null 
 277  
             && extensionPointsFigCompartment.isVisible();
 278  
     }
 279  
 
 280  
     /**
 281  
      * Set the visibility of the extension point compartment. This is
 282  
      * called from outside this class when the user sets visibility
 283  
      * explicitly through the style panel or the context sensitive
 284  
      * pop-up menu.<p>
 285  
      *
 286  
      * We don't change the size of the use case, so we just have to
 287  
      * mark the extension point elements' visibility.
 288  
      * {@link #setBounds(int, int, int, int)} will do the relayout
 289  
      * (with name in the middle) for us.<p>
 290  
      *
 291  
      * @param isVisible  <code>true</code> if the compartment should be shown,
 292  
      *                   <code>false</code> otherwise.
 293  
      */
 294  
     public void setExtensionPointsVisible(boolean isVisible) {
 295  0
         setCompartmentVisible(extensionPointsFigCompartment, isVisible);
 296  0
     }
 297  
 
 298  
     /**
 299  
      * Creates a set of handles for dragging generalization/specializations
 300  
      *   or associations.<p>
 301  
      *
 302  
      * @return  The new selection object (a GEF entity).
 303  
      */
 304  
     @Override
 305  
     public Selection makeSelection() {
 306  0
         return new SelectionUseCase(this);
 307  
     }
 308  
 
 309  
     /**
 310  
      * Compute the dimensions of an ellipse that intersects the 4 corners 
 311  
      * of the given box.
 312  
      * 
 313  
      * @param box the width and height of the box
 314  
      * @return the dimension of the ellipse
 315  
      */
 316  
     public Dimension addCompartmentBoxSurroundings(Dimension box) {
 317  0
         containerBox = box;
 318  
         
 319  
         @SuppressWarnings("unused")
 320  0
         double h = box.height;
 321  0
         double w = box.width;
 322  
 
 323  0
         int padding = Math.max((int) (w / 10.0), MIN_VERT_PADDING);
 324  0
         return calcEllipse(box, padding);
 325  
     }
 326  
 
 327  
     /**
 328  
      * A private utility to calculate the bounding oval for the given
 329  
      * rectangular text box.<p>
 330  
      *
 331  
      * To sufficiently constrain the problem, we define that there is a gap
 332  
      * given by the parameter <code>vertPadding</code> above the top of the
 333  
      * box to the top of the oval.<p>
 334  
      *
 335  
      * All computations are done in double, and then converted to integer at
 336  
      * the end.<p>
 337  
      *
 338  
      * @param rectSize     The dimensions of the rectangle to be bounded
 339  
      *
 340  
      * @param vertPadding  The padding between the top of the box and the top
 341  
      *                     of the ellipse.
 342  
      *
 343  
      * @return             The dimensions of the required oval.
 344  
      */
 345  
     private Dimension calcEllipse(Dimension rectSize, int vertPadding) {
 346  
 
 347  
         // Work out the radii of the ellipse, a and b. The top right corner of
 348  
         // the ellipse (Cartesian coordinates, centered on the origin) will be
 349  
         // at (x,y)
 350  
 
 351  
         double a;
 352  0
         double b = rectSize.height / 2.0 + vertPadding;
 353  
 
 354  0
         double x = rectSize.width / 2.0;
 355  0
         double y = rectSize.height / 2.0;
 356  
 
 357  
         // Formula for a is described in the overall class description.
 358  
 
 359  0
         a = (x * b) / Math.sqrt(b * b - y * y);
 360  
 
 361  
         // Result as integers, rounded up. We ensure that the radii are
 362  
         // integers for convenience.
 363  
 
 364  0
         return new Dimension(((int) (Math.ceil(a) + getLineWidth()) * 2),
 365  
                              ((int) (Math.ceil(b) + getLineWidth()) * 2));
 366  
     }
 367  
 
 368  
     @Override
 369  
     protected Rectangle calculateCompartmentBoxDimensions(
 370  
             int x, int y, int w, int h) {
 371  
         /* For an ellipse, we can put the box in the middle:  */
 372  0
         return new Rectangle(
 373  
                 x + (w - containerBox.width) / 2, 
 374  
                 y + (h - containerBox.height) / 2, 
 375  
                 containerBox.width, 
 376  
                 containerBox.height);
 377  
     }
 378  
 
 379  
     @Override
 380  
     protected void setCompartmentBounds(FigCompartment c, 
 381  
             Rectangle cb, Rectangle ob) {
 382  0
         Rectangle r = new Rectangle();
 383  0
         r.y = cb.y;
 384  0
         r.height = getLineWidth();
 385  0
         r.width = (int) (2.0 * (calcX(
 386  
                 ob.width / 2.0,
 387  
                 ob.height / 2.0,
 388  
                 ob.height / 2.0 - (cb.y - ob.y))));
 389  0
         r.x = cb.x + cb.width / 2 - r.width / 2;
 390  
 
 391  0
         c.setExternalSeparatorFigBounds(r);            
 392  0
         c.setBounds(cb.x, cb.y, cb.width, cb.height);
 393  0
     }
 394  
 
 395  
     /**
 396  
      * Private utility routine to work out the (positive) x coordinate of a
 397  
      * point on an oval, given the radii and y coordinate.<p>
 398  
      * TODO: Use this to calculate the separator lines!
 399  
      *
 400  
      * @param a  radius in X direction
 401  
      * @param b  radius in Y direction
 402  
      * @param y  Y coordinate
 403  
      * @return   Positive X coordinate for the given Y coordinate
 404  
      */
 405  
     private double calcX(double a, double b, double y) {
 406  0
         assert a > 0;
 407  0
         assert b > 0;
 408  0
         assert b > y;
 409  0
         return (a * Math.sqrt(b * b - y * y)) / b;
 410  
     }
 411  
 
 412  
     /**
 413  
      * Set the fill colour for the use case oval.<p>
 414  
      *
 415  
      * This involves setting the fill color of all figs, but not the bigPort.
 416  
      * Calling the super method would cause all FigGroup elements
 417  
      * to follow suit - which is not wanted for the bigPort nor the separator.
 418  
      *
 419  
      * @param col  The colour desired.
 420  
      */
 421  
     @Override
 422  
     public void setFillColor(Color col) {
 423  0
         getBigPort().setFillColor(col);
 424  0
     }
 425  
     
 426  
     public Color getFillColor() {
 427  0
         return getBigPort().getFillColor();
 428  
     }
 429  
     
 430  
     public boolean getFilled() {
 431  0
         return getBigPort().isFilled();
 432  
     }
 433  
     
 434  
     public boolean isFilled() {
 435  0
         return getBigPort().isFilled();
 436  
     }
 437  
 
 438  
     /**
 439  
      * Set whether the use case oval is to be filled.<p>
 440  
      *
 441  
      * This is overridden to have no effect as the use case is always filled
 442  
      * @param f this argument is ignored.
 443  
      */
 444  
     @Override
 445  
     public void setFilled(boolean f) {
 446  
         //
 447  0
     }
 448  
 
 449  
     /**
 450  
      * FigMyCircle is a FigCircle with corrected connectionPoint method:
 451  
      *   this methods calculates where a connected edge ends.<p>
 452  
      *   
 453  
      *   TODO: Once we are at GEF version 0.13.1M4, this whole class can be 
 454  
      *   removed, since it was taken over by GEF.
 455  
      */
 456  
     public static class FigMyCircle extends FigCircle {
 457  
         /**
 458  
          * Constructor just invokes the parent constructor.<p>
 459  
          *
 460  
          * @param x       X coordinate of the upper left corner of the bounding
 461  
          *                box.
 462  
          *
 463  
          * @param y       Y coordinate of the upper left corner of the bounding
 464  
          *                box.
 465  
          *
 466  
          * @param w       Width of the bounding box.
 467  
          *
 468  
          * @param h       Height of the bounding box.
 469  
          *
 470  
          * @param lColor  Line colour of the fig.
 471  
          *
 472  
          * @param fColor  Fill colour of the fig.
 473  
          */
 474  
         public FigMyCircle(int x, int y, int w, int h,
 475  
                            Color lColor,
 476  
                            Color fColor) {
 477  0
             super(x, y, w, h, lColor, fColor);
 478  0
         }
 479  
 
 480  
         /**
 481  
          * Constructor just invokes the parent constructor.<p>
 482  
          *
 483  
          * @param x       X coordinate of the upper left corner of the bounding
 484  
          *                box.
 485  
          *
 486  
          * @param y       Y coordinate of the upper left corner of the bounding
 487  
          *                box.
 488  
          *
 489  
          * @param w       Width of the bounding box.
 490  
          *
 491  
          * @param h       Height of the bounding box.
 492  
          */
 493  
         public FigMyCircle(int x, int y, int w, int h) {
 494  0
             super(x, y, w, h);
 495  0
         }
 496  
 
 497  
         /**
 498  
          * Compute the border point of the ellipse that is on the edge
 499  
          *   between the stored upper left corner and the given parameter.<p>
 500  
          *   
 501  
          *   TODO: Once we are at GEF version 0.13.1M4, this method 
 502  
          *   and in fact the whole class can be 
 503  
          *   removed, since it was taken over by GEF in revision 1279.
 504  
          *
 505  
          * @param anotherPt  The remote point to which an edge is drawn.
 506  
          *
 507  
          * @return           The connection point on the boundary of the
 508  
          *                   ellipse.
 509  
          */
 510  
         @Override
 511  
         public Point connectionPoint(Point anotherPt) {
 512  0
             double rx = _w / 2;
 513  0
             double ry = _h / 2;
 514  0
             double dx = anotherPt.x - (_x + rx);
 515  0
             double dy = anotherPt.y - (_y + ry);
 516  0
             double dd = ry * ry * dx * dx + rx * rx * dy * dy;
 517  0
             double mu = rx * ry / Math.sqrt(dd);
 518  
 
 519  0
             Point res =
 520  
                 new Point((int) (mu * dx + _x + rx),
 521  
                           (int) (mu * dy + _y + ry));
 522  0
             return res;
 523  
         }
 524  
 
 525  
     }
 526  
 
 527  
     /*
 528  
      * Use the code from the FigCircle, not the one from Fig.
 529  
      */
 530  
     @Override
 531  
     public Point connectionPoint(Point anotherPt) {
 532  0
         return getBigPort().connectionPoint(anotherPt);
 533  
     }
 534  
 
 535  
     @Override
 536  
     protected void updateListeners(Object oldOwner, Object newOwner) {
 537  0
         Set<Object[]> listeners = new HashSet<Object[]>();
 538  
         /* Let's register for events from all modelelements
 539  
          * that change the name or body text: 
 540  
          */
 541  0
         if (newOwner != null) {
 542  
             /* Register for name changes, added extensionPoints
 543  
              * and abstract makes the text italic.
 544  
              * All Figs need to listen to "remove", too: */
 545  0
             listeners.add(new Object[] {newOwner, 
 546  
                                 new String[] {"remove", "name", "isAbstract", 
 547  
                                     "extensionPoint", "stereotype"}});
 548  
             
 549  
             // register for extension points:
 550  0
             for (Object ep : Model.getFacade().getExtensionPoints(newOwner)) {
 551  0
                 listeners.add(new Object[] {ep, new String[] {"location", "name"}});
 552  
             }
 553  
             
 554  0
             for (Object st : Model.getFacade().getStereotypes(newOwner)) {
 555  0
                 listeners.add(new Object[] {st, "name"});
 556  
             }
 557  
         }
 558  0
         updateElementListeners(listeners);
 559  0
     }
 560  
 
 561  
     @Override
 562  
     public void renderingChanged() {
 563  0
         super.renderingChanged();
 564  0
         if (getOwner() != null) {
 565  0
             updateExtensionPoints();
 566  
         }
 567  0
     }
 568  
     
 569  
     protected void updateExtensionPoints() {
 570  0
         if (!isExtensionPointsVisible()) {
 571  0
             return;
 572  
         }
 573  0
         extensionPointsFigCompartment.populate();
 574  
 
 575  0
         setBounds(getBounds());
 576  0
         damage();
 577  0
     }
 578  
     
 579  
     /**
 580  
      * @return the Fig for the extension point compartment
 581  
      */
 582  
     public FigExtensionPointsCompartment getExtensionPointsCompartment() {
 583  
         // Set bounds will be called from our superclass constructor before
 584  
         // our constructor has run, so make sure this gets set up if needed.
 585  0
         if (extensionPointsFigCompartment == null) {
 586  0
             extensionPointsFigCompartment = new FigExtensionPointsCompartment(
 587  
                     getOwner(),
 588  
                     DEFAULT_COMPARTMENT_BOUNDS, 
 589  
                     getSettings());
 590  
         }
 591  0
         return extensionPointsFigCompartment;
 592  
     }
 593  
 
 594  
 }