Print this page
Split |
Close |
Expand all |
Collapse all |
--- old/src/share/classes/javax/swing/SpringLayout.java
+++ new/src/share/classes/javax/swing/SpringLayout.java
1 1 /*
2 2 * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved.
3 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 4 *
5 5 * This code is free software; you can redistribute it and/or modify it
6 6 * under the terms of the GNU General Public License version 2 only, as
7 7 * published by the Free Software Foundation. Oracle designates this
8 8 * particular file as subject to the "Classpath" exception as provided
9 9 * by Oracle in the LICENSE file that accompanied this code.
10 10 *
11 11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 14 * version 2 for more details (a copy is included in the LICENSE file that
15 15 * accompanied this code).
16 16 *
17 17 * You should have received a copy of the GNU General Public License version
18 18 * 2 along with this work; if not, write to the Free Software Foundation,
19 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 20 *
21 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 22 * or visit www.oracle.com if you need additional information or have any
23 23 * questions.
24 24 */
25 25 package javax.swing;
26 26
27 27 import java.awt.Component;
28 28 import java.awt.Container;
↓ open down ↓ |
28 lines elided |
↑ open up ↑ |
29 29 import java.awt.Dimension;
30 30 import java.awt.FontMetrics;
31 31 import java.awt.Insets;
32 32 import java.awt.LayoutManager2;
33 33 import java.awt.Rectangle;
34 34 import java.util.*;
35 35
36 36 /**
37 37 * A <code>SpringLayout</code> lays out the children of its associated container
38 38 * according to a set of constraints.
39 - * See <a href="http://docs.oracle.com/javase/tutorial/uiswing/layout/spring.html">How to Use SpringLayout</a>
39 + * See <a href="https://docs.oracle.com/javase/tutorial/uiswing/layout/spring.html">How to Use SpringLayout</a>
40 40 * in <em>The Java Tutorial</em> for examples of using
41 41 * <code>SpringLayout</code>.
42 42 *
43 43 * <p>
44 44 * Each constraint,
45 45 * represented by a <code>Spring</code> object,
46 46 * controls the vertical or horizontal distance
47 47 * between two component edges.
48 48 * The edges can belong to
49 49 * any child of the container,
50 50 * or to the container itself.
51 51 * For example,
52 52 * the allowable width of a component
53 53 * can be expressed using a constraint
54 54 * that controls the distance between the west (left) and east (right)
55 55 * edges of the component.
56 56 * The allowable <em>y</em> coordinates for a component
57 57 * can be expressed by constraining the distance between
58 58 * the north (top) edge of the component
59 59 * and the north edge of its container.
60 60 *
61 61 * <P>
62 62 * Every child of a <code>SpringLayout</code>-controlled container,
63 63 * as well as the container itself,
64 64 * has exactly one set of constraints
65 65 * associated with it.
66 66 * These constraints are represented by
67 67 * a <code>SpringLayout.Constraints</code> object.
68 68 * By default,
69 69 * <code>SpringLayout</code> creates constraints
70 70 * that make their associated component
71 71 * have the minimum, preferred, and maximum sizes
72 72 * returned by the component's
73 73 * {@link java.awt.Component#getMinimumSize},
74 74 * {@link java.awt.Component#getPreferredSize}, and
75 75 * {@link java.awt.Component#getMaximumSize}
76 76 * methods. The <em>x</em> and <em>y</em> positions are initially not
77 77 * constrained, so that until you constrain them the <code>Component</code>
78 78 * will be positioned at 0,0 relative to the <code>Insets</code> of the
79 79 * parent <code>Container</code>.
80 80 *
81 81 * <p>
82 82 * You can change
83 83 * a component's constraints in several ways.
84 84 * You can
85 85 * use one of the
86 86 * {@link #putConstraint putConstraint}
87 87 * methods
88 88 * to establish a spring
89 89 * linking the edges of two components within the same container.
90 90 * Or you can get the appropriate <code>SpringLayout.Constraints</code>
91 91 * object using
92 92 * {@link #getConstraints getConstraints}
93 93 * and then modify one or more of its springs.
94 94 * Or you can get the spring for a particular edge of a component
95 95 * using {@link #getConstraint getConstraint},
96 96 * and modify it.
97 97 * You can also associate
98 98 * your own <code>SpringLayout.Constraints</code> object
99 99 * with a component by specifying the constraints object
100 100 * when you add the component to its container
101 101 * (using
102 102 * {@link Container#add(Component, Object)}).
103 103 *
104 104 * <p>
105 105 * The <code>Spring</code> object representing each constraint
106 106 * has a minimum, preferred, maximum, and current value.
107 107 * The current value of the spring
108 108 * is somewhere between the minimum and maximum values,
109 109 * according to the formula given in the
110 110 * {@link Spring#sum} method description.
111 111 * When the minimum, preferred, and maximum values are the same,
112 112 * the current value is always equal to them;
113 113 * this inflexible spring is called a <em>strut</em>.
114 114 * You can create struts using the factory method
115 115 * {@link Spring#constant(int)}.
116 116 * The <code>Spring</code> class also provides factory methods
117 117 * for creating other kinds of springs,
118 118 * including springs that depend on other springs.
119 119 *
120 120 * <p>
121 121 * In a <code>SpringLayout</code>, the position of each edge is dependent on
122 122 * the position of just one other edge. If a constraint is subsequently added
123 123 * to create a new binding for an edge, the previous binding is discarded
124 124 * and the edge remains dependent on a single edge.
125 125 * Springs should only be attached
126 126 * between edges of the container and its immediate children; the behavior
127 127 * of the <code>SpringLayout</code> when presented with constraints linking
128 128 * the edges of components from different containers (either internal or
129 129 * external) is undefined.
130 130 *
131 131 * <h3>
132 132 * SpringLayout vs. Other Layout Managers
133 133 * </h3>
134 134 *
135 135 * <blockquote>
136 136 * <hr>
137 137 * <strong>Note:</strong>
138 138 * Unlike many layout managers,
139 139 * <code>SpringLayout</code> doesn't automatically set the location of
140 140 * the components it manages.
141 141 * If you hand-code a GUI that uses <code>SpringLayout</code>,
142 142 * remember to initialize component locations by constraining the west/east
143 143 * and north/south locations.
144 144 * <p>
145 145 * Depending on the constraints you use,
146 146 * you may also need to set the size of the container explicitly.
147 147 * <hr>
148 148 * </blockquote>
149 149 *
150 150 * <p>
151 151 * Despite the simplicity of <code>SpringLayout</code>,
152 152 * it can emulate the behavior of most other layout managers.
153 153 * For some features,
154 154 * such as the line breaking provided by <code>FlowLayout</code>,
155 155 * you'll need to
156 156 * create a special-purpose subclass of the <code>Spring</code> class.
157 157 *
158 158 * <p>
159 159 * <code>SpringLayout</code> also provides a way to solve
160 160 * many of the difficult layout
161 161 * problems that cannot be solved by nesting combinations
162 162 * of <code>Box</code>es. That said, <code>SpringLayout</code> honors the
163 163 * <code>LayoutManager2</code> contract correctly and so can be nested with
164 164 * other layout managers -- a technique that can be preferable to
165 165 * creating the constraints implied by the other layout managers.
166 166 * <p>
167 167 * The asymptotic complexity of the layout operation of a <code>SpringLayout</code>
168 168 * is linear in the number of constraints (and/or components).
169 169 * <p>
170 170 * <strong>Warning:</strong>
171 171 * Serialized objects of this class will not be compatible with
172 172 * future Swing releases. The current serialization support is
173 173 * appropriate for short term storage or RMI between applications running
174 174 * the same version of Swing. As of 1.4, support for long term storage
175 175 * of all JavaBeans™
176 176 * has been added to the <code>java.beans</code> package.
177 177 * Please see {@link java.beans.XMLEncoder}.
178 178 *
179 179 * @see Spring
180 180 * @see SpringLayout.Constraints
181 181 *
182 182 * @author Philip Milne
183 183 * @author Scott Violet
184 184 * @author Joe Winchester
185 185 * @since 1.4
186 186 */
187 187 public class SpringLayout implements LayoutManager2 {
188 188 private Map<Component, Constraints> componentConstraints = new HashMap<Component, Constraints>();
189 189
190 190 private Spring cyclicReference = Spring.constant(Spring.UNSET);
191 191 private Set<Spring> cyclicSprings;
192 192 private Set<Spring> acyclicSprings;
193 193
194 194
195 195 /**
196 196 * Specifies the top edge of a component's bounding rectangle.
197 197 */
198 198 public static final String NORTH = "North";
199 199
200 200 /**
201 201 * Specifies the bottom edge of a component's bounding rectangle.
202 202 */
203 203 public static final String SOUTH = "South";
204 204
205 205 /**
206 206 * Specifies the right edge of a component's bounding rectangle.
207 207 */
208 208 public static final String EAST = "East";
209 209
210 210 /**
211 211 * Specifies the left edge of a component's bounding rectangle.
212 212 */
213 213 public static final String WEST = "West";
214 214
215 215 /**
216 216 * Specifies the horizontal center of a component's bounding rectangle.
217 217 *
218 218 * @since 1.6
219 219 */
220 220 public static final String HORIZONTAL_CENTER = "HorizontalCenter";
221 221
222 222 /**
223 223 * Specifies the vertical center of a component's bounding rectangle.
224 224 *
225 225 * @since 1.6
226 226 */
227 227 public static final String VERTICAL_CENTER = "VerticalCenter";
228 228
229 229 /**
230 230 * Specifies the baseline of a component.
231 231 *
232 232 * @since 1.6
233 233 */
234 234 public static final String BASELINE = "Baseline";
235 235
236 236 /**
237 237 * Specifies the width of a component's bounding rectangle.
238 238 *
239 239 * @since 1.6
240 240 */
241 241 public static final String WIDTH = "Width";
242 242
243 243 /**
244 244 * Specifies the height of a component's bounding rectangle.
245 245 *
246 246 * @since 1.6
247 247 */
248 248 public static final String HEIGHT = "Height";
249 249
250 250 private static String[] ALL_HORIZONTAL = {WEST, WIDTH, EAST, HORIZONTAL_CENTER};
251 251
252 252 private static String[] ALL_VERTICAL = {NORTH, HEIGHT, SOUTH, VERTICAL_CENTER, BASELINE};
253 253
254 254 /**
255 255 * A <code>Constraints</code> object holds the
256 256 * constraints that govern the way a component's size and position
257 257 * change in a container controlled by a <code>SpringLayout</code>.
258 258 * A <code>Constraints</code> object is
259 259 * like a <code>Rectangle</code>, in that it
260 260 * has <code>x</code>, <code>y</code>,
261 261 * <code>width</code>, and <code>height</code> properties.
262 262 * In the <code>Constraints</code> object, however,
263 263 * these properties have
264 264 * <code>Spring</code> values instead of integers.
265 265 * In addition,
266 266 * a <code>Constraints</code> object
267 267 * can be manipulated as four edges
268 268 * -- north, south, east, and west --
269 269 * using the <code>constraint</code> property.
270 270 *
271 271 * <p>
272 272 * The following formulas are always true
273 273 * for a <code>Constraints</code> object (here WEST and <code>x</code> are synonyms, as are and NORTH and <code>y</code>):
274 274 *
275 275 * <pre>
276 276 * EAST = WEST + WIDTH
277 277 * SOUTH = NORTH + HEIGHT
278 278 * HORIZONTAL_CENTER = WEST + WIDTH/2
279 279 * VERTICAL_CENTER = NORTH + HEIGHT/2
280 280 * ABSOLUTE_BASELINE = NORTH + RELATIVE_BASELINE*
281 281 * </pre>
282 282 * <p>
283 283 * For example, if you have specified the WIDTH and WEST (X) location
284 284 * the EAST is calculated as WEST + WIDTH. If you instead specified
285 285 * the WIDTH and EAST locations the WEST (X) location is then calculated
286 286 * as EAST - WIDTH.
287 287 * <p>
288 288 * [RELATIVE_BASELINE is a private constraint that is set automatically when
289 289 * the SpringLayout.Constraints(Component) constructor is called or when
290 290 * a constraints object is registered with a SpringLayout object.]
291 291 * <p>
292 292 * <b>Note</b>: In this document,
293 293 * operators represent methods
294 294 * in the <code>Spring</code> class.
295 295 * For example, "a + b" is equal to
296 296 * <code>Spring.sum(a, b)</code>,
297 297 * and "a - b" is equal to
298 298 * <code>Spring.sum(a, Spring.minus(b))</code>.
299 299 * See the
300 300 * {@link Spring Spring API documentation}
301 301 * for further details
302 302 * of spring arithmetic.
303 303 *
304 304 * <p>
305 305 *
306 306 * Because a <code>Constraints</code> object's properties --
307 307 * representing its edges, size, and location -- can all be set
308 308 * independently and yet are interrelated,
309 309 * a <code>Constraints</code> object can become <em>over-constrained</em>.
310 310 * For example, if the <code>WEST</code>, <code>WIDTH</code> and
311 311 * <code>EAST</code> edges are all set, steps must be taken to ensure that
312 312 * the first of the formulas above holds. To do this, the
313 313 * <code>Constraints</code>
314 314 * object throws away the <em>least recently set</em>
315 315 * constraint so as to make the formulas hold.
316 316 * @since 1.4
317 317 */
318 318 public static class Constraints {
319 319 private Spring x;
320 320 private Spring y;
321 321 private Spring width;
322 322 private Spring height;
323 323 private Spring east;
324 324 private Spring south;
325 325 private Spring horizontalCenter;
326 326 private Spring verticalCenter;
327 327 private Spring baseline;
328 328
329 329 private List<String> horizontalHistory = new ArrayList<String>(2);
330 330 private List<String> verticalHistory = new ArrayList<String>(2);
331 331
332 332 // Used for baseline calculations
333 333 private Component c;
334 334
335 335 /**
336 336 * Creates an empty <code>Constraints</code> object.
337 337 */
338 338 public Constraints() {
339 339 }
340 340
341 341 /**
342 342 * Creates a <code>Constraints</code> object with the
343 343 * specified values for its
344 344 * <code>x</code> and <code>y</code> properties.
345 345 * The <code>height</code> and <code>width</code> springs
346 346 * have <code>null</code> values.
347 347 *
348 348 * @param x the spring controlling the component's <em>x</em> value
349 349 * @param y the spring controlling the component's <em>y</em> value
350 350 */
351 351 public Constraints(Spring x, Spring y) {
352 352 setX(x);
353 353 setY(y);
354 354 }
355 355
356 356 /**
357 357 * Creates a <code>Constraints</code> object with the
358 358 * specified values for its
359 359 * <code>x</code>, <code>y</code>, <code>width</code>,
360 360 * and <code>height</code> properties.
361 361 * Note: If the <code>SpringLayout</code> class
362 362 * encounters <code>null</code> values in the
363 363 * <code>Constraints</code> object of a given component,
364 364 * it replaces them with suitable defaults.
365 365 *
366 366 * @param x the spring value for the <code>x</code> property
367 367 * @param y the spring value for the <code>y</code> property
368 368 * @param width the spring value for the <code>width</code> property
369 369 * @param height the spring value for the <code>height</code> property
370 370 */
371 371 public Constraints(Spring x, Spring y, Spring width, Spring height) {
372 372 setX(x);
373 373 setY(y);
374 374 setWidth(width);
375 375 setHeight(height);
376 376 }
377 377
378 378 /**
379 379 * Creates a <code>Constraints</code> object with
380 380 * suitable <code>x</code>, <code>y</code>, <code>width</code> and
381 381 * <code>height</code> springs for component, <code>c</code>.
382 382 * The <code>x</code> and <code>y</code> springs are constant
383 383 * springs initialised with the component's location at
384 384 * the time this method is called. The <code>width</code> and
385 385 * <code>height</code> springs are special springs, created by
386 386 * the <code>Spring.width()</code> and <code>Spring.height()</code>
387 387 * methods, which track the size characteristics of the component
388 388 * when they change.
389 389 *
390 390 * @param c the component whose characteristics will be reflected by this Constraints object
391 391 * @throws NullPointerException if <code>c</code> is null.
392 392 * @since 1.5
393 393 */
394 394 public Constraints(Component c) {
395 395 this.c = c;
396 396 setX(Spring.constant(c.getX()));
397 397 setY(Spring.constant(c.getY()));
398 398 setWidth(Spring.width(c));
399 399 setHeight(Spring.height(c));
400 400 }
401 401
402 402 private void pushConstraint(String name, Spring value, boolean horizontal) {
403 403 boolean valid = true;
404 404 List<String> history = horizontal ? horizontalHistory :
405 405 verticalHistory;
406 406 if (history.contains(name)) {
407 407 history.remove(name);
408 408 valid = false;
409 409 } else if (history.size() == 2 && value != null) {
410 410 history.remove(0);
411 411 valid = false;
412 412 }
413 413 if (value != null) {
414 414 history.add(name);
415 415 }
416 416 if (!valid) {
417 417 String[] all = horizontal ? ALL_HORIZONTAL : ALL_VERTICAL;
418 418 for (String s : all) {
419 419 if (!history.contains(s)) {
420 420 setConstraint(s, null);
421 421 }
422 422 }
423 423 }
424 424 }
425 425
426 426 private Spring sum(Spring s1, Spring s2) {
427 427 return (s1 == null || s2 == null) ? null : Spring.sum(s1, s2);
428 428 }
429 429
430 430 private Spring difference(Spring s1, Spring s2) {
431 431 return (s1 == null || s2 == null) ? null : Spring.difference(s1, s2);
432 432 }
433 433
434 434 private Spring scale(Spring s, float factor) {
435 435 return (s == null) ? null : Spring.scale(s, factor);
436 436 }
437 437
438 438 private int getBaselineFromHeight(int height) {
439 439 if (height < 0) {
440 440 // Bad Scott, Bad Scott!
441 441 return -c.getBaseline(c.getPreferredSize().width,
442 442 -height);
443 443 }
444 444 return c.getBaseline(c.getPreferredSize().width, height);
445 445 }
446 446
447 447 private int getHeightFromBaseLine(int baseline) {
448 448 Dimension prefSize = c.getPreferredSize();
449 449 int prefHeight = prefSize.height;
450 450 int prefBaseline = c.getBaseline(prefSize.width, prefHeight);
451 451 if (prefBaseline == baseline) {
452 452 // If prefBaseline < 0, then no baseline, assume preferred
453 453 // height.
454 454 // If prefBaseline == baseline, then specified baseline
455 455 // matches preferred baseline, return preferred height
456 456 return prefHeight;
457 457 }
458 458 // Valid baseline
459 459 switch(c.getBaselineResizeBehavior()) {
460 460 case CONSTANT_DESCENT:
461 461 return prefHeight + (baseline - prefBaseline);
462 462 case CENTER_OFFSET:
463 463 return prefHeight + 2 * (baseline - prefBaseline);
464 464 case CONSTANT_ASCENT:
465 465 // Component baseline and specified baseline will NEVER
466 466 // match, fall through to default
467 467 default: // OTHER
468 468 // No way to map from baseline to height.
469 469 }
470 470 return Integer.MIN_VALUE;
471 471 }
472 472
473 473 private Spring heightToRelativeBaseline(Spring s) {
474 474 return new Spring.SpringMap(s) {
475 475 protected int map(int i) {
476 476 return getBaselineFromHeight(i);
477 477 }
478 478
479 479 protected int inv(int i) {
480 480 return getHeightFromBaseLine(i);
481 481 }
482 482 };
483 483 }
484 484
485 485 private Spring relativeBaselineToHeight(Spring s) {
486 486 return new Spring.SpringMap(s) {
487 487 protected int map(int i) {
488 488 return getHeightFromBaseLine(i);
489 489 }
490 490
491 491 protected int inv(int i) {
492 492 return getBaselineFromHeight(i);
493 493 }
494 494 };
495 495 }
496 496
497 497 private boolean defined(List history, String s1, String s2) {
498 498 return history.contains(s1) && history.contains(s2);
499 499 }
500 500
501 501 /**
502 502 * Sets the <code>x</code> property,
503 503 * which controls the <code>x</code> value
504 504 * of a component's location.
505 505 *
506 506 * @param x the spring controlling the <code>x</code> value
507 507 * of a component's location
508 508 *
509 509 * @see #getX
510 510 * @see SpringLayout.Constraints
511 511 */
512 512 public void setX(Spring x) {
513 513 this.x = x;
514 514 pushConstraint(WEST, x, true);
515 515 }
516 516
517 517 /**
518 518 * Returns the value of the <code>x</code> property.
519 519 *
520 520 * @return the spring controlling the <code>x</code> value
521 521 * of a component's location
522 522 *
523 523 * @see #setX
524 524 * @see SpringLayout.Constraints
525 525 */
526 526 public Spring getX() {
527 527 if (x == null) {
528 528 if (defined(horizontalHistory, EAST, WIDTH)) {
529 529 x = difference(east, width);
530 530 } else if (defined(horizontalHistory, HORIZONTAL_CENTER, WIDTH)) {
531 531 x = difference(horizontalCenter, scale(width, 0.5f));
532 532 } else if (defined(horizontalHistory, HORIZONTAL_CENTER, EAST)) {
533 533 x = difference(scale(horizontalCenter, 2f), east);
534 534 }
535 535 }
536 536 return x;
537 537 }
538 538
539 539 /**
540 540 * Sets the <code>y</code> property,
541 541 * which controls the <code>y</code> value
542 542 * of a component's location.
543 543 *
544 544 * @param y the spring controlling the <code>y</code> value
545 545 * of a component's location
546 546 *
547 547 * @see #getY
548 548 * @see SpringLayout.Constraints
549 549 */
550 550 public void setY(Spring y) {
551 551 this.y = y;
552 552 pushConstraint(NORTH, y, false);
553 553 }
554 554
555 555 /**
556 556 * Returns the value of the <code>y</code> property.
557 557 *
558 558 * @return the spring controlling the <code>y</code> value
559 559 * of a component's location
560 560 *
561 561 * @see #setY
562 562 * @see SpringLayout.Constraints
563 563 */
564 564 public Spring getY() {
565 565 if (y == null) {
566 566 if (defined(verticalHistory, SOUTH, HEIGHT)) {
567 567 y = difference(south, height);
568 568 } else if (defined(verticalHistory, VERTICAL_CENTER, HEIGHT)) {
569 569 y = difference(verticalCenter, scale(height, 0.5f));
570 570 } else if (defined(verticalHistory, VERTICAL_CENTER, SOUTH)) {
571 571 y = difference(scale(verticalCenter, 2f), south);
572 572 } else if (defined(verticalHistory, BASELINE, HEIGHT)) {
573 573 y = difference(baseline, heightToRelativeBaseline(height));
574 574 } else if (defined(verticalHistory, BASELINE, SOUTH)) {
575 575 y = scale(difference(baseline, heightToRelativeBaseline(south)), 2f);
576 576 /*
577 577 } else if (defined(verticalHistory, BASELINE, VERTICAL_CENTER)) {
578 578 y = scale(difference(baseline, heightToRelativeBaseline(scale(verticalCenter, 2))), 1f/(1-2*0.5f));
579 579 */
580 580 }
581 581 }
582 582 return y;
583 583 }
584 584
585 585 /**
586 586 * Sets the <code>width</code> property,
587 587 * which controls the width of a component.
588 588 *
589 589 * @param width the spring controlling the width of this
590 590 * <code>Constraints</code> object
591 591 *
592 592 * @see #getWidth
593 593 * @see SpringLayout.Constraints
594 594 */
595 595 public void setWidth(Spring width) {
596 596 this.width = width;
597 597 pushConstraint(WIDTH, width, true);
598 598 }
599 599
600 600 /**
601 601 * Returns the value of the <code>width</code> property.
602 602 *
603 603 * @return the spring controlling the width of a component
604 604 *
605 605 * @see #setWidth
606 606 * @see SpringLayout.Constraints
607 607 */
608 608 public Spring getWidth() {
609 609 if (width == null) {
610 610 if (horizontalHistory.contains(EAST)) {
611 611 width = difference(east, getX());
612 612 } else if (horizontalHistory.contains(HORIZONTAL_CENTER)) {
613 613 width = scale(difference(horizontalCenter, getX()), 2f);
614 614 }
615 615 }
616 616 return width;
617 617 }
618 618
619 619 /**
620 620 * Sets the <code>height</code> property,
621 621 * which controls the height of a component.
622 622 *
623 623 * @param height the spring controlling the height of this <code>Constraints</code>
624 624 * object
625 625 *
626 626 * @see #getHeight
627 627 * @see SpringLayout.Constraints
628 628 */
629 629 public void setHeight(Spring height) {
630 630 this.height = height;
631 631 pushConstraint(HEIGHT, height, false);
632 632 }
633 633
634 634 /**
635 635 * Returns the value of the <code>height</code> property.
636 636 *
637 637 * @return the spring controlling the height of a component
638 638 *
639 639 * @see #setHeight
640 640 * @see SpringLayout.Constraints
641 641 */
642 642 public Spring getHeight() {
643 643 if (height == null) {
644 644 if (verticalHistory.contains(SOUTH)) {
645 645 height = difference(south, getY());
646 646 } else if (verticalHistory.contains(VERTICAL_CENTER)) {
647 647 height = scale(difference(verticalCenter, getY()), 2f);
648 648 } else if (verticalHistory.contains(BASELINE)) {
649 649 height = relativeBaselineToHeight(difference(baseline, getY()));
650 650 }
651 651 }
652 652 return height;
653 653 }
654 654
655 655 private void setEast(Spring east) {
656 656 this.east = east;
657 657 pushConstraint(EAST, east, true);
658 658 }
659 659
660 660 private Spring getEast() {
661 661 if (east == null) {
662 662 east = sum(getX(), getWidth());
663 663 }
664 664 return east;
665 665 }
666 666
667 667 private void setSouth(Spring south) {
668 668 this.south = south;
669 669 pushConstraint(SOUTH, south, false);
670 670 }
671 671
672 672 private Spring getSouth() {
673 673 if (south == null) {
674 674 south = sum(getY(), getHeight());
675 675 }
676 676 return south;
677 677 }
678 678
679 679 private Spring getHorizontalCenter() {
680 680 if (horizontalCenter == null) {
681 681 horizontalCenter = sum(getX(), scale(getWidth(), 0.5f));
682 682 }
683 683 return horizontalCenter;
684 684 }
685 685
686 686 private void setHorizontalCenter(Spring horizontalCenter) {
687 687 this.horizontalCenter = horizontalCenter;
688 688 pushConstraint(HORIZONTAL_CENTER, horizontalCenter, true);
689 689 }
690 690
691 691 private Spring getVerticalCenter() {
692 692 if (verticalCenter == null) {
693 693 verticalCenter = sum(getY(), scale(getHeight(), 0.5f));
694 694 }
695 695 return verticalCenter;
696 696 }
697 697
698 698 private void setVerticalCenter(Spring verticalCenter) {
699 699 this.verticalCenter = verticalCenter;
700 700 pushConstraint(VERTICAL_CENTER, verticalCenter, false);
701 701 }
702 702
703 703 private Spring getBaseline() {
704 704 if (baseline == null) {
705 705 baseline = sum(getY(), heightToRelativeBaseline(getHeight()));
706 706 }
707 707 return baseline;
708 708 }
709 709
710 710 private void setBaseline(Spring baseline) {
711 711 this.baseline = baseline;
712 712 pushConstraint(BASELINE, baseline, false);
713 713 }
714 714
715 715 /**
716 716 * Sets the spring controlling the specified edge.
717 717 * The edge must have one of the following values:
718 718 * <code>SpringLayout.NORTH</code>,
719 719 * <code>SpringLayout.SOUTH</code>,
720 720 * <code>SpringLayout.EAST</code>,
721 721 * <code>SpringLayout.WEST</code>,
722 722 * <code>SpringLayout.HORIZONTAL_CENTER</code>,
723 723 * <code>SpringLayout.VERTICAL_CENTER</code>,
724 724 * <code>SpringLayout.BASELINE</code>,
725 725 * <code>SpringLayout.WIDTH</code> or
726 726 * <code>SpringLayout.HEIGHT</code>.
727 727 * For any other <code>String</code> value passed as the edge,
728 728 * no action is taken. For a <code>null</code> edge, a
729 729 * <code>NullPointerException</code> is thrown.
730 730 * <p>
731 731 * <b>Note:</b> This method can affect {@code x} and {@code y} values
732 732 * previously set for this {@code Constraints}.
733 733 *
734 734 * @param edgeName the edge to be set
735 735 * @param s the spring controlling the specified edge
736 736 *
737 737 * @throws NullPointerException if <code>edgeName</code> is <code>null</code>
738 738 *
739 739 * @see #getConstraint
740 740 * @see #NORTH
741 741 * @see #SOUTH
742 742 * @see #EAST
743 743 * @see #WEST
744 744 * @see #HORIZONTAL_CENTER
745 745 * @see #VERTICAL_CENTER
746 746 * @see #BASELINE
747 747 * @see #WIDTH
748 748 * @see #HEIGHT
749 749 * @see SpringLayout.Constraints
750 750 */
751 751 public void setConstraint(String edgeName, Spring s) {
752 752 edgeName = edgeName.intern();
753 753 if (edgeName == WEST) {
754 754 setX(s);
755 755 } else if (edgeName == NORTH) {
756 756 setY(s);
757 757 } else if (edgeName == EAST) {
758 758 setEast(s);
759 759 } else if (edgeName == SOUTH) {
760 760 setSouth(s);
761 761 } else if (edgeName == HORIZONTAL_CENTER) {
762 762 setHorizontalCenter(s);
763 763 } else if (edgeName == WIDTH) {
764 764 setWidth(s);
765 765 } else if (edgeName == HEIGHT) {
766 766 setHeight(s);
767 767 } else if (edgeName == VERTICAL_CENTER) {
768 768 setVerticalCenter(s);
769 769 } else if (edgeName == BASELINE) {
770 770 setBaseline(s);
771 771 }
772 772 }
773 773
774 774 /**
775 775 * Returns the value of the specified edge, which may be
776 776 * a derived value, or even <code>null</code>.
777 777 * The edge must have one of the following values:
778 778 * <code>SpringLayout.NORTH</code>,
779 779 * <code>SpringLayout.SOUTH</code>,
780 780 * <code>SpringLayout.EAST</code>,
781 781 * <code>SpringLayout.WEST</code>,
782 782 * <code>SpringLayout.HORIZONTAL_CENTER</code>,
783 783 * <code>SpringLayout.VERTICAL_CENTER</code>,
784 784 * <code>SpringLayout.BASELINE</code>,
785 785 * <code>SpringLayout.WIDTH</code> or
786 786 * <code>SpringLayout.HEIGHT</code>.
787 787 * For any other <code>String</code> value passed as the edge,
788 788 * <code>null</code> will be returned. Throws
789 789 * <code>NullPointerException</code> for a <code>null</code> edge.
790 790 *
791 791 * @param edgeName the edge whose value
792 792 * is to be returned
793 793 *
794 794 * @return the spring controlling the specified edge, may be <code>null</code>
795 795 *
796 796 * @throws NullPointerException if <code>edgeName</code> is <code>null</code>
797 797 *
798 798 * @see #setConstraint
799 799 * @see #NORTH
800 800 * @see #SOUTH
801 801 * @see #EAST
802 802 * @see #WEST
803 803 * @see #HORIZONTAL_CENTER
804 804 * @see #VERTICAL_CENTER
805 805 * @see #BASELINE
806 806 * @see #WIDTH
807 807 * @see #HEIGHT
808 808 * @see SpringLayout.Constraints
809 809 */
810 810 public Spring getConstraint(String edgeName) {
811 811 edgeName = edgeName.intern();
812 812 return (edgeName == WEST) ? getX() :
813 813 (edgeName == NORTH) ? getY() :
814 814 (edgeName == EAST) ? getEast() :
815 815 (edgeName == SOUTH) ? getSouth() :
816 816 (edgeName == WIDTH) ? getWidth() :
817 817 (edgeName == HEIGHT) ? getHeight() :
818 818 (edgeName == HORIZONTAL_CENTER) ? getHorizontalCenter() :
819 819 (edgeName == VERTICAL_CENTER) ? getVerticalCenter() :
820 820 (edgeName == BASELINE) ? getBaseline() :
821 821 null;
822 822 }
823 823
824 824 /*pp*/ void reset() {
825 825 Spring[] allSprings = {x, y, width, height, east, south,
826 826 horizontalCenter, verticalCenter, baseline};
827 827 for (Spring s : allSprings) {
828 828 if (s != null) {
829 829 s.setValue(Spring.UNSET);
830 830 }
831 831 }
832 832 }
833 833 }
834 834
835 835 private static class SpringProxy extends Spring {
836 836 private String edgeName;
837 837 private Component c;
838 838 private SpringLayout l;
839 839
840 840 public SpringProxy(String edgeName, Component c, SpringLayout l) {
841 841 this.edgeName = edgeName;
842 842 this.c = c;
843 843 this.l = l;
844 844 }
845 845
846 846 private Spring getConstraint() {
847 847 return l.getConstraints(c).getConstraint(edgeName);
848 848 }
849 849
850 850 public int getMinimumValue() {
851 851 return getConstraint().getMinimumValue();
852 852 }
853 853
854 854 public int getPreferredValue() {
855 855 return getConstraint().getPreferredValue();
856 856 }
857 857
858 858 public int getMaximumValue() {
859 859 return getConstraint().getMaximumValue();
860 860 }
861 861
862 862 public int getValue() {
863 863 return getConstraint().getValue();
864 864 }
865 865
866 866 public void setValue(int size) {
867 867 getConstraint().setValue(size);
868 868 }
869 869
870 870 /*pp*/ boolean isCyclic(SpringLayout l) {
871 871 return l.isCyclic(getConstraint());
872 872 }
873 873
874 874 public String toString() {
875 875 return "SpringProxy for " + edgeName + " edge of " + c.getName() + ".";
876 876 }
877 877 }
878 878
879 879 /**
880 880 * Constructs a new <code>SpringLayout</code>.
881 881 */
882 882 public SpringLayout() {}
883 883
884 884 private void resetCyclicStatuses() {
885 885 cyclicSprings = new HashSet<Spring>();
886 886 acyclicSprings = new HashSet<Spring>();
887 887 }
888 888
889 889 private void setParent(Container p) {
890 890 resetCyclicStatuses();
891 891 Constraints pc = getConstraints(p);
892 892
893 893 pc.setX(Spring.constant(0));
894 894 pc.setY(Spring.constant(0));
895 895 // The applyDefaults() method automatically adds width and
896 896 // height springs that delegate their calculations to the
897 897 // getMinimumSize(), getPreferredSize() and getMaximumSize()
898 898 // methods of the relevant component. In the case of the
899 899 // parent this will cause an infinite loop since these
900 900 // methods, in turn, delegate their calculations to the
901 901 // layout manager. Check for this case and replace the
902 902 // the springs that would cause this problem with a
903 903 // constant springs that supply default values.
904 904 Spring width = pc.getWidth();
905 905 if (width instanceof Spring.WidthSpring && ((Spring.WidthSpring)width).c == p) {
906 906 pc.setWidth(Spring.constant(0, 0, Integer.MAX_VALUE));
907 907 }
908 908 Spring height = pc.getHeight();
909 909 if (height instanceof Spring.HeightSpring && ((Spring.HeightSpring)height).c == p) {
910 910 pc.setHeight(Spring.constant(0, 0, Integer.MAX_VALUE));
911 911 }
912 912 }
913 913
914 914 /*pp*/ boolean isCyclic(Spring s) {
915 915 if (s == null) {
916 916 return false;
917 917 }
918 918 if (cyclicSprings.contains(s)) {
919 919 return true;
920 920 }
921 921 if (acyclicSprings.contains(s)) {
922 922 return false;
923 923 }
924 924 cyclicSprings.add(s);
925 925 boolean result = s.isCyclic(this);
926 926 if (!result) {
927 927 acyclicSprings.add(s);
928 928 cyclicSprings.remove(s);
929 929 }
930 930 else {
931 931 System.err.println(s + " is cyclic. ");
932 932 }
933 933 return result;
934 934 }
935 935
936 936 private Spring abandonCycles(Spring s) {
937 937 return isCyclic(s) ? cyclicReference : s;
938 938 }
939 939
940 940 // LayoutManager methods.
941 941
942 942 /**
943 943 * Has no effect,
944 944 * since this layout manager does not
945 945 * use a per-component string.
946 946 */
947 947 public void addLayoutComponent(String name, Component c) {}
948 948
949 949 /**
950 950 * Removes the constraints associated with the specified component.
951 951 *
952 952 * @param c the component being removed from the container
953 953 */
954 954 public void removeLayoutComponent(Component c) {
955 955 componentConstraints.remove(c);
956 956 }
957 957
958 958 private static Dimension addInsets(int width, int height, Container p) {
959 959 Insets i = p.getInsets();
960 960 return new Dimension(width + i.left + i.right, height + i.top + i.bottom);
961 961 }
962 962
963 963 public Dimension minimumLayoutSize(Container parent) {
964 964 setParent(parent);
965 965 Constraints pc = getConstraints(parent);
966 966 return addInsets(abandonCycles(pc.getWidth()).getMinimumValue(),
967 967 abandonCycles(pc.getHeight()).getMinimumValue(),
968 968 parent);
969 969 }
970 970
971 971 public Dimension preferredLayoutSize(Container parent) {
972 972 setParent(parent);
973 973 Constraints pc = getConstraints(parent);
974 974 return addInsets(abandonCycles(pc.getWidth()).getPreferredValue(),
975 975 abandonCycles(pc.getHeight()).getPreferredValue(),
976 976 parent);
977 977 }
978 978
979 979 // LayoutManager2 methods.
980 980
981 981 public Dimension maximumLayoutSize(Container parent) {
982 982 setParent(parent);
983 983 Constraints pc = getConstraints(parent);
984 984 return addInsets(abandonCycles(pc.getWidth()).getMaximumValue(),
985 985 abandonCycles(pc.getHeight()).getMaximumValue(),
986 986 parent);
987 987 }
988 988
989 989 /**
990 990 * If <code>constraints</code> is an instance of
991 991 * <code>SpringLayout.Constraints</code>,
992 992 * associates the constraints with the specified component.
993 993 * <p>
994 994 * @param component the component being added
995 995 * @param constraints the component's constraints
996 996 *
997 997 * @see SpringLayout.Constraints
998 998 */
999 999 public void addLayoutComponent(Component component, Object constraints) {
1000 1000 if (constraints instanceof Constraints) {
1001 1001 putConstraints(component, (Constraints)constraints);
1002 1002 }
1003 1003 }
1004 1004
1005 1005 /**
1006 1006 * Returns 0.5f (centered).
1007 1007 */
1008 1008 public float getLayoutAlignmentX(Container p) {
1009 1009 return 0.5f;
1010 1010 }
1011 1011
1012 1012 /**
1013 1013 * Returns 0.5f (centered).
1014 1014 */
1015 1015 public float getLayoutAlignmentY(Container p) {
1016 1016 return 0.5f;
1017 1017 }
1018 1018
1019 1019 public void invalidateLayout(Container p) {}
1020 1020
1021 1021 // End of LayoutManger2 methods
1022 1022
1023 1023 /**
1024 1024 * Links edge <code>e1</code> of component <code>c1</code> to
1025 1025 * edge <code>e2</code> of component <code>c2</code>,
1026 1026 * with a fixed distance between the edges. This
1027 1027 * constraint will cause the assignment
1028 1028 * <pre>
1029 1029 * value(e1, c1) = value(e2, c2) + pad</pre>
1030 1030 * to take place during all subsequent layout operations.
1031 1031 * <p>
1032 1032 * @param e1 the edge of the dependent
1033 1033 * @param c1 the component of the dependent
1034 1034 * @param pad the fixed distance between dependent and anchor
1035 1035 * @param e2 the edge of the anchor
1036 1036 * @param c2 the component of the anchor
1037 1037 *
1038 1038 * @see #putConstraint(String, Component, Spring, String, Component)
1039 1039 */
1040 1040 public void putConstraint(String e1, Component c1, int pad, String e2, Component c2) {
1041 1041 putConstraint(e1, c1, Spring.constant(pad), e2, c2);
1042 1042 }
1043 1043
1044 1044 /**
1045 1045 * Links edge <code>e1</code> of component <code>c1</code> to
1046 1046 * edge <code>e2</code> of component <code>c2</code>. As edge
1047 1047 * <code>(e2, c2)</code> changes value, edge <code>(e1, c1)</code> will
1048 1048 * be calculated by taking the (spring) sum of <code>(e2, c2)</code>
1049 1049 * and <code>s</code>.
1050 1050 * Each edge must have one of the following values:
1051 1051 * <code>SpringLayout.NORTH</code>,
1052 1052 * <code>SpringLayout.SOUTH</code>,
1053 1053 * <code>SpringLayout.EAST</code>,
1054 1054 * <code>SpringLayout.WEST</code>,
1055 1055 * <code>SpringLayout.VERTICAL_CENTER</code>,
1056 1056 * <code>SpringLayout.HORIZONTAL_CENTER</code> or
1057 1057 * <code>SpringLayout.BASELINE</code>.
1058 1058 * <p>
1059 1059 * @param e1 the edge of the dependent
1060 1060 * @param c1 the component of the dependent
1061 1061 * @param s the spring linking dependent and anchor
1062 1062 * @param e2 the edge of the anchor
1063 1063 * @param c2 the component of the anchor
1064 1064 *
1065 1065 * @see #putConstraint(String, Component, int, String, Component)
1066 1066 * @see #NORTH
1067 1067 * @see #SOUTH
1068 1068 * @see #EAST
1069 1069 * @see #WEST
1070 1070 * @see #VERTICAL_CENTER
1071 1071 * @see #HORIZONTAL_CENTER
1072 1072 * @see #BASELINE
1073 1073 */
1074 1074 public void putConstraint(String e1, Component c1, Spring s, String e2, Component c2) {
1075 1075 putConstraint(e1, c1, Spring.sum(s, getConstraint(e2, c2)));
1076 1076 }
1077 1077
1078 1078 private void putConstraint(String e, Component c, Spring s) {
1079 1079 if (s != null) {
1080 1080 getConstraints(c).setConstraint(e, s);
1081 1081 }
1082 1082 }
1083 1083
1084 1084 private Constraints applyDefaults(Component c, Constraints constraints) {
1085 1085 if (constraints == null) {
1086 1086 constraints = new Constraints();
1087 1087 }
1088 1088 if (constraints.c == null) {
1089 1089 constraints.c = c;
1090 1090 }
1091 1091 if (constraints.horizontalHistory.size() < 2) {
1092 1092 applyDefaults(constraints, WEST, Spring.constant(0), WIDTH,
1093 1093 Spring.width(c), constraints.horizontalHistory);
1094 1094 }
1095 1095 if (constraints.verticalHistory.size() < 2) {
1096 1096 applyDefaults(constraints, NORTH, Spring.constant(0), HEIGHT,
1097 1097 Spring.height(c), constraints.verticalHistory);
1098 1098 }
1099 1099 return constraints;
1100 1100 }
1101 1101
1102 1102 private void applyDefaults(Constraints constraints, String name1,
1103 1103 Spring spring1, String name2, Spring spring2,
1104 1104 List<String> history) {
1105 1105 if (history.size() == 0) {
1106 1106 constraints.setConstraint(name1, spring1);
1107 1107 constraints.setConstraint(name2, spring2);
1108 1108 } else {
1109 1109 // At this point there must be exactly one constraint defined already.
1110 1110 // Check width/height first.
1111 1111 if (constraints.getConstraint(name2) == null) {
1112 1112 constraints.setConstraint(name2, spring2);
1113 1113 } else {
1114 1114 // If width/height is already defined, install a default for x/y.
1115 1115 constraints.setConstraint(name1, spring1);
1116 1116 }
1117 1117 // Either way, leave the user's constraint topmost on the stack.
1118 1118 Collections.rotate(history, 1);
1119 1119 }
1120 1120 }
1121 1121
1122 1122 private void putConstraints(Component component, Constraints constraints) {
1123 1123 componentConstraints.put(component, applyDefaults(component, constraints));
1124 1124 }
1125 1125
1126 1126 /**
1127 1127 * Returns the constraints for the specified component.
1128 1128 * Note that,
1129 1129 * unlike the <code>GridBagLayout</code>
1130 1130 * <code>getConstraints</code> method,
1131 1131 * this method does not clone constraints.
1132 1132 * If no constraints
1133 1133 * have been associated with this component,
1134 1134 * this method
1135 1135 * returns a default constraints object positioned at
1136 1136 * 0,0 relative to the parent's Insets and its width/height
1137 1137 * constrained to the minimum, maximum, and preferred sizes of the
1138 1138 * component. The size characteristics
1139 1139 * are not frozen at the time this method is called;
1140 1140 * instead this method returns a constraints object
1141 1141 * whose characteristics track the characteristics
1142 1142 * of the component as they change.
1143 1143 *
1144 1144 * @param c the component whose constraints will be returned
1145 1145 *
1146 1146 * @return the constraints for the specified component
1147 1147 */
1148 1148 public Constraints getConstraints(Component c) {
1149 1149 Constraints result = componentConstraints.get(c);
1150 1150 if (result == null) {
1151 1151 if (c instanceof javax.swing.JComponent) {
1152 1152 Object cp = ((javax.swing.JComponent)c).getClientProperty(SpringLayout.class);
1153 1153 if (cp instanceof Constraints) {
1154 1154 return applyDefaults(c, (Constraints)cp);
1155 1155 }
1156 1156 }
1157 1157 result = new Constraints();
1158 1158 putConstraints(c, result);
1159 1159 }
1160 1160 return result;
1161 1161 }
1162 1162
1163 1163 /**
1164 1164 * Returns the spring controlling the distance between
1165 1165 * the specified edge of
1166 1166 * the component and the top or left edge of its parent. This
1167 1167 * method, instead of returning the current binding for the
1168 1168 * edge, returns a proxy that tracks the characteristics
1169 1169 * of the edge even if the edge is subsequently rebound.
1170 1170 * Proxies are intended to be used in builder environments
1171 1171 * where it is useful to allow the user to define the
1172 1172 * constraints for a layout in any order. Proxies do, however,
1173 1173 * provide the means to create cyclic dependencies amongst
1174 1174 * the constraints of a layout. Such cycles are detected
1175 1175 * internally by <code>SpringLayout</code> so that
1176 1176 * the layout operation always terminates.
1177 1177 *
1178 1178 * @param edgeName must be one of
1179 1179 * <code>SpringLayout.NORTH</code>,
1180 1180 * <code>SpringLayout.SOUTH</code>,
1181 1181 * <code>SpringLayout.EAST</code>,
1182 1182 * <code>SpringLayout.WEST</code>,
1183 1183 * <code>SpringLayout.VERTICAL_CENTER</code>,
1184 1184 * <code>SpringLayout.HORIZONTAL_CENTER</code> or
1185 1185 * <code>SpringLayout.BASELINE</code>
1186 1186 * @param c the component whose edge spring is desired
1187 1187 *
1188 1188 * @return a proxy for the spring controlling the distance between the
1189 1189 * specified edge and the top or left edge of its parent
1190 1190 *
1191 1191 * @see #NORTH
1192 1192 * @see #SOUTH
1193 1193 * @see #EAST
1194 1194 * @see #WEST
1195 1195 * @see #VERTICAL_CENTER
1196 1196 * @see #HORIZONTAL_CENTER
1197 1197 * @see #BASELINE
1198 1198 */
1199 1199 public Spring getConstraint(String edgeName, Component c) {
1200 1200 // The interning here is unnecessary; it was added for efficiency.
1201 1201 edgeName = edgeName.intern();
1202 1202 return new SpringProxy(edgeName, c, this);
1203 1203 }
1204 1204
1205 1205 public void layoutContainer(Container parent) {
1206 1206 setParent(parent);
1207 1207
1208 1208 int n = parent.getComponentCount();
1209 1209 getConstraints(parent).reset();
1210 1210 for (int i = 0 ; i < n ; i++) {
1211 1211 getConstraints(parent.getComponent(i)).reset();
1212 1212 }
1213 1213
1214 1214 Insets insets = parent.getInsets();
1215 1215 Constraints pc = getConstraints(parent);
1216 1216 abandonCycles(pc.getX()).setValue(0);
1217 1217 abandonCycles(pc.getY()).setValue(0);
1218 1218 abandonCycles(pc.getWidth()).setValue(parent.getWidth() -
1219 1219 insets.left - insets.right);
1220 1220 abandonCycles(pc.getHeight()).setValue(parent.getHeight() -
1221 1221 insets.top - insets.bottom);
1222 1222
1223 1223 for (int i = 0 ; i < n ; i++) {
1224 1224 Component c = parent.getComponent(i);
1225 1225 Constraints cc = getConstraints(c);
1226 1226 int x = abandonCycles(cc.getX()).getValue();
1227 1227 int y = abandonCycles(cc.getY()).getValue();
1228 1228 int width = abandonCycles(cc.getWidth()).getValue();
1229 1229 int height = abandonCycles(cc.getHeight()).getValue();
1230 1230 c.setBounds(insets.left + x, insets.top + y, width, height);
1231 1231 }
1232 1232 }
1233 1233 }
↓ open down ↓ |
1184 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX