Classes in this File | Line Coverage | Branch Coverage | Complexity | ||||
FigUseCase |
|
| 1.4074074074074074;1.407 | ||||
FigUseCase$FigMyCircle |
|
| 1.4074074074074074;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 | } |