KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > javax > swing > SpringLayout


1 /*
2  * @(#)SpringLayout.java 1.19 03/12/19
3  *
4  * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
5  * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
6  */

7 package javax.swing;
8
9 import java.awt.*;
10 import java.util.*;
11
12 /**
13  * A <code>SpringLayout</code> lays out the children of its associated container
14  * according to a set of constraints.
15  * See <a HREF="http://java.sun.com/docs/books/tutorial/uiswing/layout/spring.html">How to Use SpringLayout</a>
16  * in <em>The Java Tutorial</em> for examples of using
17  * <code>SpringLayout</code>.
18  *
19  * <p>
20  * Each constraint,
21  * represented by a <code>Spring</code> object,
22  * controls the vertical or horizontal distance
23  * between two component edges.
24  * The edges can belong to
25  * any child of the container,
26  * or to the container itself.
27  * For example,
28  * the allowable width of a component
29  * can be expressed using a constraint
30  * that controls the distance between the west (left) and east (right)
31  * edges of the component.
32  * The allowable <em>y</em> coordinates for a component
33  * can be expressed by constraining the distance between
34  * the north (top) edge of the component
35  * and the north edge of its container.
36  *
37  * <P>
38  * Every child of a <code>SpringLayout</code>-controlled container,
39  * as well as the container itself,
40  * has exactly one set of constraints
41  * associated with it.
42  * These constraints are represented by
43  * a <code>SpringLayout.Constraints</code> object.
44  * By default,
45  * <code>SpringLayout</code> creates constraints
46  * that make their associated component
47  * have the minimum, preferred, and maximum sizes
48  * returned by the component's
49  * {@link java.awt.Component#getMinimumSize},
50  * {@link java.awt.Component#getPreferredSize}, and
51  * {@link java.awt.Component#getMaximumSize}
52  * methods. The <em>x</em> and <em>y</em> positions are initially not
53  * constrained, so that until you constrain them the <code>Component</code>
54  * will be positioned at 0,0 relative to the <code>Insets</code> of the
55  * parent <code>Container</code>.
56  *
57  * <p>
58  * You can change
59  * a component's constraints in several ways.
60  * You can
61  * use one of the
62  * {@link #putConstraint putConstraint}
63  * methods
64  * to establish a spring
65  * linking the edges of two components within the same container.
66  * Or you can get the appropriate <code>SpringLayout.Constraints</code>
67  * object using
68  * {@link #getConstraints getConstraints}
69  * and then modify one or more of its springs.
70  * Or you can get the spring for a particular edge of a component
71  * using {@link #getConstraint getConstraint},
72  * and modify it.
73  * You can also associate
74  * your own <code>SpringLayout.Constraints</code> object
75  * with a component by specifying the constraints object
76  * when you add the component to its container
77  * (using
78  * {@link Container#add(Component, Object)}).
79  *
80  * <p>
81  * The <code>Spring</code> object representing each constraint
82  * has a minimum, preferred, maximum, and current value.
83  * The current value of the spring
84  * is somewhere between the minimum and maximum values,
85  * according to the formula given in the
86  * {@link Spring#sum} method description.
87  * When the minimum, preferred, and maximum values are the same,
88  * the current value is always equal to them;
89  * this inflexible spring is called a <em>strut</em>.
90  * You can create struts using the factory method
91  * {@link Spring#constant(int)}.
92  * The <code>Spring</code> class also provides factory methods
93  * for creating other kinds of springs,
94  * including springs that depend on other springs.
95  *
96  * <p>
97  * In a <code>SpringLayout</code>, the position of each edge is dependent on
98  * the position of just one other edge. If a constraint is subsequently added
99  * to create a new binding for an edge, the previous binding is discarded
100  * and the edge remains dependent on a single edge.
101  * Springs should only be attached
102  * between edges of the container and its immediate children; the behavior
103  * of the <code>SpringLayout</code> when presented with constraints linking
104  * the edges of components from different containers (either internal or
105  * external) is undefined.
106  *
107  * <h3>
108  * SpringLayout vs. Other Layout Managers
109  * </h3>
110  *
111  * <blockquote>
112  * <hr>
113  * <strong>Note:</strong>
114  * Unlike many layout managers,
115  * <code>SpringLayout</code> doesn't automatically set the location of
116  * the components it manages.
117  * If you hand-code a GUI that uses <code>SpringLayout</code>,
118  * remember to initialize component locations by constraining the west/east
119  * and north/south locations.
120  * <p>
121  * Depending on the constraints you use,
122  * you may also need to set the size of the container explicitly.
123  * <hr>
124  * </blockquote>
125  *
126  * <p>
127  * Despite the simplicity of <code>SpringLayout</code>,
128  * it can emulate the behavior of most other layout managers.
129  * For some features,
130  * such as the line breaking provided by <code>FlowLayout</code>,
131  * you'll need to
132  * create a special-purpose subclass of the <code>Spring</code> class.
133  *
134  * <p>
135  * <code>SpringLayout</code> also provides a way to solve
136  * many of the difficult layout
137  * problems that cannot be solved by nesting combinations
138  * of <code>Box</code>es. That said, <code>SpringLayout</code> honors the
139  * <code>LayoutManager2</code> contract correctly and so can be nested with
140  * other layout managers -- a technique that can be preferable to
141  * creating the constraints implied by the other layout managers.
142  * <p>
143  * The asymptotic complexity of the layout operation of a <code>SpringLayout</code>
144  * is linear in the number of constraints (and/or components).
145  * <p>
146  * <strong>Warning:</strong>
147  * Serialized objects of this class will not be compatible with
148  * future Swing releases. The current serialization support is
149  * appropriate for short term storage or RMI between applications running
150  * the same version of Swing. As of 1.4, support for long term storage
151  * of all JavaBeans<sup><font size="-2">TM</font></sup>
152  * has been added to the <code>java.beans</code> package.
153  * Please see {@link java.beans.XMLEncoder}.
154  *
155  * @see Spring
156  * @see SpringLayout.Constraints
157  *
158  * @version 1.19 12/19/03
159  * @author Philip Milne
160  * @author Joe Winchester
161  * @since 1.4
162  */

163 public class SpringLayout implements LayoutManager2 {
164     private Map componentConstraints = new HashMap();
165
166     private Spring JavaDoc cyclicReference = Spring.constant(Spring.UNSET);
167     private Set cyclicSprings;
168     private Set acyclicSprings;
169
170
171     /**
172      * Specifies the top edge of a component's bounding rectangle.
173      */

174     public static final String JavaDoc NORTH = "North";
175
176     /**
177      * Specifies the bottom edge of a component's bounding rectangle.
178      */

179     public static final String JavaDoc SOUTH = "South";
180
181     /**
182      * Specifies the right edge of a component's bounding rectangle.
183      */

184     public static final String JavaDoc EAST = "East";
185
186     /**
187      * Specifies the left edge of a component's bounding rectangle.
188      */

189     public static final String JavaDoc WEST = "West";
190
191
192     /**
193      * A <code>Constraints</code> object holds the
194      * constraints that govern the way a component's size and position
195      * change in a container controlled by a <code>SpringLayout</code>.
196      * A <code>Constraints</code> object is
197      * like a <code>Rectangle</code>, in that it
198      * has <code>x</code>, <code>y</code>,
199      * <code>width</code>, and <code>height</code> properties.
200      * In the <code>Constraints</code> object, however,
201      * these properties have
202      * <code>Spring</code> values instead of integers.
203      * In addition,
204      * a <code>Constraints</code> object
205      * can be manipulated as four edges
206      * -- north, south, east, and west --
207      * using the <code>constraint</code> property.
208      *
209      * <p>
210      * The following formulas are always true
211      * for a <code>Constraints</code> object:
212      *
213      * <pre>
214      * west = x
215      * north = y
216      * east = x + width
217      * south = y + height</pre>
218      *
219      * <b>Note</b>: In this document,
220      * operators represent methods
221      * in the <code>Spring</code> class.
222      * For example, "a + b" is equal to
223      * <code>Spring.sum(a, b)</code>,
224      * and "a - b" is equal to
225      * <code>Spring.sum(a, Spring.minus(b))</code>.
226      * See the
227      * {@link Spring Spring</code> API documentation<code>}
228      * for further details
229      * of spring arithmetic.
230      *
231      * <p>
232      *
233      * Because a <code>Constraints</code> object's properties --
234      * representing its edges, size, and location -- can all be set
235      * independently and yet are interrelated,
236      * the object can become <em>over-constrained</em>.
237      * For example,
238      * if both the <code>x</code> and <code>width</code>
239      * properties are set
240      * and then the east edge is set,
241      * the object is over-constrained horizontally.
242      * When this happens, one of the values
243      * (in this case, the <code>x</code> property)
244      * automatically changes so
245      * that the formulas still hold.
246      *
247      * <p>
248      * The following table shows which value changes
249      * when a <code>Constraints</code> object
250      * is over-constrained horizontally.
251      *
252      * <p>
253      *
254      * <table border=1 summary="Shows which value changes when a Constraints object is over-constrained horizontally">
255      * <tr>
256      * <th valign=top>Value Being Set<br>(method used)</th>
257      * <th valign=top>Result When Over-Constrained Horizontally<br>
258      * (<code>x</code>, <code>width</code>, and the east edge are all non-<code>null</code>)</th>
259      * </tr>
260      * <tr>
261      * <td><code>x</code> or the west edge <br>(<code>setX</code> or <code>setConstraint</code>)</td>
262      * <td><code>width</code> value is automatically set to <code>east - x</code>.</td>
263      * </tr>
264      * <tr>
265      * <td><code>width</code><br>(<code>setWidth</code>)</td>
266      * <td>east edge's value is automatically set to <code>x + width</code>.</td>
267      * </tr>
268      * <tr>
269      * <td>east edge<br>(<code>setConstraint</code>)</td>
270      * <td><code>x</code> value is automatically set to <code>east - width</code>.</td>
271      * </tr>
272      * </table>
273      *
274      * <p>
275      * The rules for the vertical properties are similar:
276      * <p>
277      *
278      * <table border=1 summary="Shows which value changes when a Constraints object is over-constrained vertically">
279      * <tr>
280      * <th valign=top>Value Being Set<br>(method used)</th>
281      * <th valign=top>Result When Over-Constrained Vertically<br>(<code>y</code>, <code>height</code>, and the south edge are all non-<code>null</code>)</th>
282      * </tr>
283      * <tr>
284      * <td><code>y</code> or the north edge<br>(<code>setY</code> or <code>setConstraint</code>)</td>
285      * <td><code>height</code> value is automatically set to <code>south - y</code>.</td>
286      * </tr>
287      * <tr>
288      * <td><code>height</code><br>(<code>setHeight</code>)</td>
289      * <td>south edge's value is automatically set to <code>y + height</code>.</td>
290      * </tr>
291      * <tr>
292      * <td>south edge<br>(<code>setConstraint</code>)</td>
293      * <td><code>y</code> value is automatically set to <code>south - height</code>.</td>
294      * </tr>
295      * </table>
296      *
297      */

298    public static class Constraints {
299        private Spring JavaDoc x;
300        private Spring JavaDoc y;
301        private Spring JavaDoc width;
302        private Spring JavaDoc height;
303        private Spring JavaDoc east;
304        private Spring JavaDoc south;
305
306        private Spring JavaDoc verticalDerived = null;
307        private Spring JavaDoc horizontalDerived = null;
308        
309        /**
310         * Creates an empty <code>Constraints</code> object.
311         */

312        public Constraints() {
313            this(null, null, null, null);
314        }
315
316        /**
317         * Creates a <code>Constraints</code> object with the
318     * specified values for its
319         * <code>x</code> and <code>y</code> properties.
320         * The <code>height</code> and <code>width</code> springs
321     * have <code>null</code> values.
322         *
323         * @param x the spring controlling the component's <em>x</em> value
324         * @param y the spring controlling the component's <em>y</em> value
325         */

326        public Constraints(Spring JavaDoc x, Spring JavaDoc y) {
327            this(x, y, null, null);
328        }
329
330        /**
331         * Creates a <code>Constraints</code> object with the
332     * specified values for its
333         * <code>x</code>, <code>y</code>, <code>width</code>,
334     * and <code>height</code> properties.
335         * Note: If the <code>SpringLayout</code> class
336     * encounters <code>null</code> values in the
337     * <code>Constraints</code> object of a given component,
338     * it replaces them with suitable defaults.
339         *
340         * @param x the spring value for the <code>x</code> property
341         * @param y the spring value for the <code>y</code> property
342         * @param width the spring value for the <code>width</code> property
343         * @param height the spring value for the <code>height</code> property
344         */

345        public Constraints(Spring JavaDoc x, Spring JavaDoc y, Spring JavaDoc width, Spring JavaDoc height) {
346            this.x = x;
347            this.y = y;
348            this.width = width;
349            this.height = height;
350        }
351
352         /**
353          * Creates a <code>Constraints</code> object with
354          * suitable <code>x</code>, <code>y</code>, <code>width</code> and
355          * <code>height</code> springs for component, <code>c</code>.
356          * The <code>x</code> and <code>y</code> springs are constant
357          * springs initialised with the component's location at
358          * the time this method is called. The <code>width</code> and
359          * <code>height</code> springs are special springs, created by
360          * the <code>Spring.width()</code> and <code>Spring.height()</code>
361          * methods, which track the size characteristics of the component
362          * when they change.
363          *
364          * @param c the component whose characteristics will be reflected by this Constraints object
365          * @throws NullPointerException if <code>c</code> is null.
366          * @since 1.5
367          */

368         public Constraints(Component c) {
369             this.x = Spring.constant(c.getX());
370             this.y = Spring.constant(c.getY());
371             this.width = Spring.width(c);
372             this.height = Spring.height(c);
373         }
374
375        private boolean overConstrainedHorizontally() {
376            return (x != null) && (width != null) && (east != null);
377        }
378        
379        private boolean overConstrainedVertically() {
380            return (y != null) && (height != null) && (south != null);
381        }
382        
383        private Spring JavaDoc sum(Spring JavaDoc s1, Spring JavaDoc s2) {
384            return (s1 == null || s2 == null) ? null : Spring.sum(s1, s2);
385        }
386         
387        private Spring JavaDoc difference(Spring JavaDoc s1, Spring JavaDoc s2) {
388            return (s1 == null || s2 == null) ? null : Spring.difference(s1, s2);
389        }
390         
391        /**
392         * Sets the <code>x</code> property,
393     * which controls the <code>x</code> value
394     * of a component's location.
395         *
396         * @param x the spring controlling the <code>x</code> value
397     * of a component's location
398         *
399         * @see #getX
400         * @see SpringLayout.Constraints
401         */

402        public void setX(Spring JavaDoc x) {
403            this.x = x;
404            horizontalDerived = null;
405            if (overConstrainedHorizontally()) {
406                width = null;
407            }
408        }
409
410        /**
411         * Returns the value of the <code>x</code> property.
412         *
413         * @return the spring controlling the <code>x</code> value
414     * of a component's location
415         *
416         * @see #setX
417         * @see SpringLayout.Constraints
418         */

419        public Spring JavaDoc getX() {
420            if (x != null) {
421                return x;
422            }
423            if (horizontalDerived == null) {
424                horizontalDerived = difference(east, width);
425            }
426            return horizontalDerived;
427        }
428
429        /**
430         * Sets the <code>y</code> property,
431     * which controls the <code>y</code> value
432     * of a component's location.
433         *
434         * @param y the spring controlling the <code>y</code> value
435     * of a component's location
436         *
437         * @see #getY
438         * @see SpringLayout.Constraints
439         */

440        public void setY(Spring JavaDoc y) {
441            this.y = y;
442            verticalDerived = null;
443            if (overConstrainedVertically()) {
444                height = null;
445            }
446        }
447
448        /**
449         * Returns the value of the <code>y</code> property.
450         *
451         * @return the spring controlling the <code>y</code> value
452     * of a component's location
453         *
454         * @see #setY
455         * @see SpringLayout.Constraints
456         */

457        public Spring JavaDoc getY() {
458            if (y != null) {
459                return y;
460            }
461            if (verticalDerived == null) {
462                verticalDerived = difference(south, height);
463            }
464            return verticalDerived;
465        }
466
467        /**
468         * Sets the <code>width</code> property,
469     * which controls the width of a component.
470         *
471         * @param width the spring controlling the width of this
472     * <code>Constraints</code> object
473         *
474         * @see #getWidth
475         * @see SpringLayout.Constraints
476         */

477        public void setWidth(Spring JavaDoc width) {
478            this.width = width;
479            horizontalDerived = null;
480            if (overConstrainedHorizontally()) {
481                east = null;
482            }
483        }
484
485        /**
486         * Returns the value of the <code>width</code> property.
487         *
488         * @return the spring controlling the width of a component
489         *
490         * @see #setWidth
491         * @see SpringLayout.Constraints
492         */

493        public Spring JavaDoc getWidth() {
494            if (width != null) {
495                return width;
496            }
497            if (horizontalDerived == null) {
498                horizontalDerived = difference(east, x);
499            }
500            return horizontalDerived;
501        }
502
503        /**
504         * Sets the <code>height</code> property,
505     * which controls the height of a component.
506         *
507         * @param height the spring controlling the height of this <code>Constraints</code>
508     * object
509         *
510         * @see #getHeight
511         * @see SpringLayout.Constraints
512         */

513        public void setHeight(Spring JavaDoc height) {
514            this.height = height;
515            verticalDerived = null;
516            if (overConstrainedVertically()) {
517                south = null;
518            }
519        }
520
521        /**
522         * Returns the value of the <code>height</code> property.
523         *
524         * @return the spring controlling the height of a component
525         *
526         * @see #setHeight
527         * @see SpringLayout.Constraints
528         */

529        public Spring JavaDoc getHeight() {
530            if (height != null) {
531                return height;
532            }
533            if (verticalDerived == null) {
534                verticalDerived = difference(south, y);
535            }
536            return verticalDerived;
537        }
538
539        private void setEast(Spring JavaDoc east) {
540            this.east = east;
541            horizontalDerived = null;
542            if (overConstrainedHorizontally()) {
543                x = null;
544            }
545        }
546
547        private Spring JavaDoc getEast() {
548            if (east != null) {
549                return east;
550            }
551            if (horizontalDerived == null) {
552                horizontalDerived = sum(x, width);
553            }
554            return horizontalDerived;
555        }
556
557        private void setSouth(Spring JavaDoc south) {
558            this.south = south;
559            verticalDerived = null;
560            if (overConstrainedVertically()) {
561                y = null;
562            }
563        }
564
565        private Spring JavaDoc getSouth() {
566            if (south != null) {
567                return south;
568            }
569            if (verticalDerived == null) {
570                verticalDerived = sum(y, height);
571            }
572            return verticalDerived;
573        }
574
575        /**
576         * Sets the spring controlling the specified edge.
577         * The edge must have one of the following values:
578         * <code>SpringLayout.NORTH</code>, <code>SpringLayout.SOUTH</code>,
579     * <code>SpringLayout.EAST</code>, <code>SpringLayout.WEST</code>.
580         *
581         * @param edgeName the edge to be set
582         * @param s the spring controlling the specified edge
583         *
584         * @see #getConstraint
585     * @see #NORTH
586     * @see #SOUTH
587     * @see #EAST
588     * @see #WEST
589         * @see SpringLayout.Constraints
590         */

591        public void setConstraint(String JavaDoc edgeName, Spring JavaDoc s) {
592            edgeName = edgeName.intern();
593            if (edgeName == "West") {
594                setX(s);
595            }
596            else if (edgeName == "North") {
597                setY(s);
598            }
599            else if (edgeName == "East") {
600                setEast(s);
601            }
602            else if (edgeName == "South") {
603                setSouth(s);
604            }
605        }
606
607        /**
608         * Returns the value of the specified edge.
609         * The edge must have one of the following values:
610         * <code>SpringLayout.NORTH</code>, <code>SpringLayout.SOUTH</code>,
611     * <code>SpringLayout.EAST</code>, <code>SpringLayout.WEST</code>.
612         *
613         * @param edgeName the edge whose value
614     * is to be returned
615         *
616         * @return the spring controlling the specified edge
617         *
618         * @see #setConstraint
619     * @see #NORTH
620     * @see #SOUTH
621     * @see #EAST
622     * @see #WEST
623         * @see SpringLayout.Constraints
624         */

625        public Spring JavaDoc getConstraint(String JavaDoc edgeName) {
626            edgeName = edgeName.intern();
627            return (edgeName == "West") ? getX() :
628                   (edgeName == "North") ? getY() :
629                   (edgeName == "East") ? getEast() :
630                   (edgeName == "South") ? getSouth() :
631                   null;
632        }
633
634        /*pp*/ void reset() {
635            if (x != null) x.setValue(Spring.UNSET);
636            if (y != null) y.setValue(Spring.UNSET);
637            if (width != null) width.setValue(Spring.UNSET);
638            if (height != null) height.setValue(Spring.UNSET);
639            if (east != null) east.setValue(Spring.UNSET);
640            if (south != null) south.setValue(Spring.UNSET);
641            if (horizontalDerived != null) horizontalDerived.setValue(Spring.UNSET);
642            if (verticalDerived != null) verticalDerived.setValue(Spring.UNSET);
643        }
644    }
645
646    private static class SpringProxy extends Spring JavaDoc {
647        private String JavaDoc edgeName;
648        private Component c;
649        private SpringLayout JavaDoc l;
650
651        public SpringProxy(String JavaDoc edgeName, Component c, SpringLayout JavaDoc l) {
652            this.edgeName = edgeName;
653            this.c = c;
654            this.l = l;
655        }
656
657        private Spring JavaDoc getConstraint() {
658            return l.getConstraints(c).getConstraint(edgeName);
659        }
660
661        public int getMinimumValue() {
662            return getConstraint().getMinimumValue();
663        }
664
665        public int getPreferredValue() {
666            return getConstraint().getPreferredValue();
667        }
668
669        public int getMaximumValue() {
670            return getConstraint().getMaximumValue();
671        }
672
673        public int getValue() {
674            return getConstraint().getValue();
675        }
676
677        public void setValue(int size) {
678            getConstraint().setValue(size);
679        }
680
681        /*pp*/ boolean isCyclic(SpringLayout JavaDoc l) {
682            return l.isCyclic(getConstraint());
683        }
684
685        public String JavaDoc toString() {
686            return "SpringProxy for " + edgeName + " edge of " + c.getName() + ".";
687        }
688     }
689
690     /**
691      * Constructs a new <code>SpringLayout</code>.
692      */

693     public SpringLayout() {}
694
695     private void resetCyclicStatuses() {
696         cyclicSprings = new HashSet();
697         acyclicSprings = new HashSet();
698     }
699
700     private void setParent(Container p) {
701         resetCyclicStatuses();
702         Constraints pc = getConstraints(p);
703         
704         pc.setX(Spring.constant(0));
705         pc.setY(Spring.constant(0));
706         // The applyDefaults() method automatically adds width and
707
// height springs that delegate their calculations to the
708
// getMinimumSize(), getPreferredSize() and getMaximumSize()
709
// methods of the relevant component. In the case of the
710
// parent this will cause an infinite loop since these
711
// methods, in turn, delegate their calculations to the
712
// layout manager. Check for this case and replace the
713
// the springs that would cause this problem with a
714
// constant springs that supply default values.
715
Spring JavaDoc width = pc.getWidth();
716         if (width instanceof Spring.WidthSpring JavaDoc && ((Spring.WidthSpring JavaDoc)width).c == p) {
717             pc.setWidth(Spring.constant(0, 0, Integer.MAX_VALUE));
718         }
719         Spring JavaDoc height = pc.getHeight();
720         if (height instanceof Spring.HeightSpring JavaDoc && ((Spring.HeightSpring JavaDoc)height).c == p) {
721             pc.setHeight(Spring.constant(0, 0, Integer.MAX_VALUE));
722         }
723     }
724
725     /*pp*/ boolean isCyclic(Spring JavaDoc s) {
726         if (s == null) {
727             return false;
728         }
729         if (cyclicSprings.contains(s)) {
730             return true;
731         }
732         if (acyclicSprings.contains(s)) {
733             return false;
734         }
735         cyclicSprings.add(s);
736         boolean result = s.isCyclic(this);
737         if (!result) {
738             acyclicSprings.add(s);
739             cyclicSprings.remove(s);
740         }
741         else {
742             System.err.println(s + " is cyclic. ");
743         }
744         return result;
745     }
746
747     private Spring JavaDoc abandonCycles(Spring JavaDoc s) {
748         return isCyclic(s) ? cyclicReference : s;
749     }
750
751     // LayoutManager methods.
752

753     /**
754      * Has no effect,
755      * since this layout manager does not
756      * use a per-component string.
757      */

758     public void addLayoutComponent(String JavaDoc name, Component c) {}
759
760     /**
761      * Removes the constraints associated with the specified component.
762      *
763      * @param c the component being removed from the container
764      */

765     public void removeLayoutComponent(Component c) {
766         componentConstraints.remove(c);
767     }
768
769     private static Dimension addInsets(int width, int height, Container p) {
770         Insets i = p.getInsets();
771         return new Dimension(width + i.left + i.right, height + i.top + i.bottom);
772     }
773
774     public Dimension minimumLayoutSize(Container parent) {
775         setParent(parent);
776         Constraints pc = getConstraints(parent);
777         return addInsets(abandonCycles(pc.getWidth()).getMinimumValue(),
778                          abandonCycles(pc.getHeight()).getMinimumValue(),
779                          parent);
780     }
781
782     public Dimension preferredLayoutSize(Container parent) {
783         setParent(parent);
784         Constraints pc = getConstraints(parent);
785         return addInsets(abandonCycles(pc.getWidth()).getPreferredValue(),
786                          abandonCycles(pc.getHeight()).getPreferredValue(),
787                          parent);
788     }
789
790     // LayoutManager2 methods.
791

792     public Dimension maximumLayoutSize(Container parent) {
793         setParent(parent);
794         Constraints pc = getConstraints(parent);
795         return addInsets(abandonCycles(pc.getWidth()).getMaximumValue(),
796                          abandonCycles(pc.getHeight()).getMaximumValue(),
797                          parent);
798     }
799
800     /**
801      * If <code>constraints</code> is an instance of
802      * <code>SpringLayout.Constraints</code>,
803      * associates the constraints with the specified component.
804      * <p>
805      * @param component the component being added
806      * @param constraints the component's constraints
807      *
808      * @see SpringLayout.Constraints
809      */

810     public void addLayoutComponent(Component component, Object JavaDoc constraints) {
811         if (constraints instanceof Constraints) {
812             putConstraints(component, (Constraints)constraints);
813         }
814     }
815
816     /**
817      * Returns 0.5f (centered).
818      */

819     public float getLayoutAlignmentX(Container p) {
820         return 0.5f;
821     }
822
823     /**
824      * Returns 0.5f (centered).
825      */

826     public float getLayoutAlignmentY(Container p) {
827         return 0.5f;
828     }
829
830     public void invalidateLayout(Container p) {}
831
832     // End of LayoutManger2 methods
833

834    /**
835      * Links edge <code>e1</code> of component <code>c1</code> to
836      * edge <code>e2</code> of component <code>c2</code>,
837      * with a fixed distance between the edges. This
838      * constraint will cause the assignment
839      * <pre>
840      * value(e1, c1) = value(e2, c2) + pad</pre>
841      * to take place during all subsequent layout operations.
842      * <p>
843      * @param e1 the edge of the dependent
844      * @param c1 the component of the dependent
845      * @param pad the fixed distance between dependent and anchor
846      * @param e2 the edge of the anchor
847      * @param c2 the component of the anchor
848      *
849      * @see #putConstraint(String, Component, Spring, String, Component)
850      */

851     public void putConstraint(String JavaDoc e1, Component c1, int pad, String JavaDoc e2, Component c2) {
852         putConstraint(e1, c1, Spring.constant(pad), e2, c2);
853     }
854
855     /**
856      * Links edge <code>e1</code> of component <code>c1</code> to
857      * edge <code>e2</code> of component <code>c2</code>. As edge
858      * <code>(e2, c2)</code> changes value, edge <code>(e1, c1)</code> will
859      * be calculated by taking the (spring) sum of <code>(e2, c2)</code>
860      * and <code>s</code>. Each edge must have one of the following values:
861      * <code>SpringLayout.NORTH</code>, <code>SpringLayout.SOUTH</code>,
862      * <code>SpringLayout.EAST</code>, <code>SpringLayout.WEST</code>.
863      * <p>
864      * @param e1 the edge of the dependent
865      * @param c1 the component of the dependent
866      * @param s the spring linking dependent and anchor
867      * @param e2 the edge of the anchor
868      * @param c2 the component of the anchor
869      *
870      * @see #putConstraint(String, Component, int, String, Component)
871      * @see #NORTH
872      * @see #SOUTH
873      * @see #EAST
874      * @see #WEST
875      */

876     public void putConstraint(String JavaDoc e1, Component c1, Spring JavaDoc s, String JavaDoc e2, Component c2) {
877         putConstraint(e1, c1, Spring.sum(s, getConstraint(e2, c2)));
878     }
879
880     private void putConstraint(String JavaDoc e, Component c, Spring JavaDoc s) {
881         if (s != null) {
882             getConstraints(c).setConstraint(e, s);
883         }
884      }
885
886     private Constraints applyDefaults(Component c, Constraints constraints) {
887         if (constraints == null) {
888            constraints = new Constraints();
889         }
890         if (constraints.getWidth() == null) {
891             constraints.setWidth(new Spring.WidthSpring JavaDoc(c));
892         }
893         if (constraints.getHeight() == null) {
894             constraints.setHeight(new Spring.HeightSpring JavaDoc(c));
895         }
896         if (constraints.getX() == null) {
897             constraints.setX(Spring.constant(0));
898         }
899         if (constraints.getY() == null) {
900             constraints.setY(Spring.constant(0));
901         }
902         return constraints;
903     }
904
905     private void putConstraints(Component component, Constraints constraints) {
906         componentConstraints.put(component, applyDefaults(component, constraints));
907     }
908
909     /**
910      * Returns the constraints for the specified component.
911      * Note that,
912      * unlike the <code>GridBagLayout</code>
913      * <code>getConstraints</code> method,
914      * this method does not clone constraints.
915      * If no constraints
916      * have been associated with this component,
917      * this method
918      * returns a default constraints object positioned at
919      * 0,0 relative to the parent's Insets and its width/height
920      * constrained to the minimum, maximum, and preferred sizes of the
921      * component. The size characteristics
922      * are not frozen at the time this method is called;
923      * instead this method returns a constraints object
924      * whose characteristics track the characteristics
925      * of the component as they change.
926      *
927      * @param c the component whose constraints will be returned
928      *
929      * @return the constraints for the specified component
930      */

931     public Constraints getConstraints(Component c) {
932        Constraints result = (Constraints)componentConstraints.get(c);
933        if (result == null) {
934            if (c instanceof javax.swing.JComponent JavaDoc) {
935                 Object JavaDoc cp = ((javax.swing.JComponent JavaDoc)c).getClientProperty(SpringLayout JavaDoc.class);
936                 if (cp instanceof Constraints) {
937                     return applyDefaults(c, (Constraints)cp);
938                 }
939             }
940             result = new Constraints();
941             putConstraints(c, result);
942        }
943        return result;
944     }
945
946     /**
947      * Returns the spring controlling the distance between
948      * the specified edge of
949      * the component and the top or left edge of its parent. This
950      * method, instead of returning the current binding for the
951      * edge, returns a proxy that tracks the characteristics
952      * of the edge even if the edge is subsequently rebound.
953      * Proxies are intended to be used in builder envonments
954      * where it is useful to allow the user to define the
955      * constraints for a layout in any order. Proxies do, however,
956      * provide the means to create cyclic dependencies amongst
957      * the constraints of a layout. Such cycles are detected
958      * internally by <code>SpringLayout</code> so that
959      * the layout operation always terminates.
960      *
961      * @param edgeName must be
962      * <code>SpringLayout.NORTH</code>,
963      * <code>SpringLayout.SOUTH</code>,
964      * <code>SpringLayout.EAST</code>, or
965      * <code>SpringLayout.WEST</code>
966      * @param c the component whose edge spring is desired
967      *
968      * @return a proxy for the spring controlling the distance between the
969      * specified edge and the top or left edge of its parent
970      *
971      * @see #NORTH
972      * @see #SOUTH
973      * @see #EAST
974      * @see #WEST
975      */

976     public Spring JavaDoc getConstraint(String JavaDoc edgeName, Component c) {
977         // The interning here is unnecessary; it was added for efficiency.
978
edgeName = edgeName.intern();
979         return new SpringProxy(edgeName, c, this);
980     }
981
982     public void layoutContainer(Container parent) {
983         setParent(parent);
984
985         int n = parent.getComponentCount();
986         getConstraints(parent).reset();
987         for (int i = 0 ; i < n ; i++) {
988             getConstraints(parent.getComponent(i)).reset();
989         }
990
991         Insets insets = parent.getInsets();
992         Constraints pc = getConstraints(parent);
993         abandonCycles(pc.getX()).setValue(0);
994         abandonCycles(pc.getY()).setValue(0);
995         abandonCycles(pc.getWidth()).setValue(parent.getWidth() -
996                                               insets.left - insets.right);
997         abandonCycles(pc.getHeight()).setValue(parent.getHeight() -
998                                                insets.top - insets.bottom);
999         
1000        for (int i = 0 ; i < n ; i++) {
1001        Component c = parent.getComponent(i);
1002            Constraints cc = getConstraints(c);
1003            int x = abandonCycles(cc.getX()).getValue();
1004            int y = abandonCycles(cc.getY()).getValue();
1005            int width = abandonCycles(cc.getWidth()).getValue();
1006            int height = abandonCycles(cc.getHeight()).getValue();
1007            c.setBounds(insets.left + x, insets.top + y, width, height);
1008    }
1009    }
1010}
1011
Popular Tags