Source Code Cross Referenced for SpringLayout.java in  » 6.0-JDK-Core » swing » javax » swing » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Home
Java Source Code / Java Documentation
1.6.0 JDK Core
2.6.0 JDK Modules
3.6.0 JDK Modules com.sun
4.6.0 JDK Modules com.sun.java
5.6.0 JDK Modules sun
6.6.0 JDK Platform
7.Ajax
8.Apache Harmony Java SE
9.Aspect oriented
10.Authentication Authorization
11.Blogger System
12.Build
13.Byte Code
14.Cache
15.Chart
16.Chat
17.Code Analyzer
18.Collaboration
19.Content Management System
20.Database Client
21.Database DBMS
22.Database JDBC Connection Pool
23.Database ORM
24.Development
25.EJB Server
26.ERP CRM Financial
27.ESB
28.Forum
29.Game
30.GIS
31.Graphic 3D
32.Graphic Library
33.Groupware
34.HTML Parser
35.IDE
36.IDE Eclipse
37.IDE Netbeans
38.Installer
39.Internationalization Localization
40.Inversion of Control
41.Issue Tracking
42.J2EE
43.J2ME
44.JBoss
45.JMS
46.JMX
47.Library
48.Mail Clients
49.Music
50.Net
51.Parser
52.PDF
53.Portal
54.Profiler
55.Project Management
56.Report
57.RSS RDF
58.Rule Engine
59.Science
60.Scripting
61.Search Engine
62.Security
63.Sevlet Container
64.Source Control
65.Swing Library
66.Template Engine
67.Test Coverage
68.Testing
69.UML
70.Web Crawler
71.Web Framework
72.Web Mail
73.Web Server
74.Web Services
75.Web Services apache cxf 2.2.6
76.Web Services AXIS2
77.Wiki Engine
78.Workflow Engines
79.XML
80.XML UI
Java Source Code / Java Documentation » 6.0 JDK Core » swing » javax.swing 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001        /*
0002         * Copyright 2001-2006 Sun Microsystems, Inc.  All Rights Reserved.
0003         * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0004         *
0005         * This code is free software; you can redistribute it and/or modify it
0006         * under the terms of the GNU General Public License version 2 only, as
0007         * published by the Free Software Foundation.  Sun designates this
0008         * particular file as subject to the "Classpath" exception as provided
0009         * by Sun in the LICENSE file that accompanied this code.
0010         *
0011         * This code is distributed in the hope that it will be useful, but WITHOUT
0012         * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0013         * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
0014         * version 2 for more details (a copy is included in the LICENSE file that
0015         * accompanied this code).
0016         *
0017         * You should have received a copy of the GNU General Public License version
0018         * 2 along with this work; if not, write to the Free Software Foundation,
0019         * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0020         *
0021         * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
0022         * CA 95054 USA or visit www.sun.com if you need additional information or
0023         * have any questions.
0024         */
0025        package javax.swing;
0026
0027        import java.awt.Component;
0028        import java.awt.Container;
0029        import java.awt.Dimension;
0030        import java.awt.FontMetrics;
0031        import java.awt.Insets;
0032        import java.awt.LayoutManager2;
0033        import java.awt.Rectangle;
0034        import java.util.*;
0035
0036        /**
0037         * A <code>SpringLayout</code> lays out the children of its associated container
0038         * according to a set of constraints.
0039         * See <a href="http://java.sun.com/docs/books/tutorial/uiswing/layout/spring.html">How to Use SpringLayout</a>
0040         * in <em>The Java Tutorial</em> for examples of using
0041         * <code>SpringLayout</code>.
0042         *
0043         * <p>
0044         * Each constraint,
0045         * represented by a <code>Spring</code> object,
0046         * controls the vertical or horizontal distance
0047         * between two component edges.
0048         * The edges can belong to
0049         * any child of the container,
0050         * or to the container itself.
0051         * For example,
0052         * the allowable width of a component
0053         * can be expressed using a constraint
0054         * that controls the distance between the west (left) and east (right) 
0055         * edges of the component.
0056         * The allowable <em>y</em> coordinates for a component
0057         * can be expressed by constraining the distance between
0058         * the north (top) edge of the component
0059         * and the north edge of its container.
0060         *
0061         * <P>
0062         * Every child of a <code>SpringLayout</code>-controlled container,
0063         * as well as the container itself,
0064         * has exactly one set of constraints
0065         * associated with it.
0066         * These constraints are represented by
0067         * a <code>SpringLayout.Constraints</code> object.
0068         * By default,
0069         * <code>SpringLayout</code> creates constraints
0070         * that make their associated component
0071         * have the minimum, preferred, and maximum sizes
0072         * returned by the component's
0073         * {@link java.awt.Component#getMinimumSize},
0074         * {@link java.awt.Component#getPreferredSize}, and
0075         * {@link java.awt.Component#getMaximumSize}
0076         * methods. The <em>x</em> and <em>y</em> positions are initially not
0077         * constrained, so that until you constrain them the <code>Component</code>
0078         * will be positioned at 0,0 relative to the <code>Insets</code> of the
0079         * parent <code>Container</code>.
0080         * 
0081         * <p>
0082         * You can change 
0083         * a component's constraints in several ways.
0084         * You can 
0085         * use one of the 
0086         * {@link #putConstraint putConstraint}
0087         * methods
0088         * to establish a spring
0089         * linking the edges of two components within the same container.
0090         * Or you can get the appropriate <code>SpringLayout.Constraints</code>
0091         * object using 
0092         * {@link #getConstraints getConstraints}
0093         * and then modify one or more of its springs.
0094         * Or you can get the spring for a particular edge of a component
0095         * using {@link #getConstraint getConstraint},
0096         * and modify it.
0097         * You can also associate
0098         * your own <code>SpringLayout.Constraints</code> object 
0099         * with a component by specifying the constraints object
0100         * when you add the component to its container
0101         * (using 
0102         * {@link Container#add(Component, Object)}).
0103         *
0104         * <p>
0105         * The <code>Spring</code> object representing each constraint 
0106         * has a minimum, preferred, maximum, and current value.
0107         * The current value of the spring 
0108         * is somewhere between the minimum and maximum values,
0109         * according to the formula given in the
0110         * {@link Spring#sum} method description.
0111         * When the minimum, preferred, and maximum values are the same,
0112         * the current value is always equal to them;
0113         * this inflexible spring is called a <em>strut</em>.
0114         * You can create struts using the factory method
0115         * {@link Spring#constant(int)}.
0116         * The <code>Spring</code> class also provides factory methods
0117         * for creating other kinds of springs,
0118         * including springs that depend on other springs.
0119         *
0120         * <p>
0121         * In a <code>SpringLayout</code>, the position of each edge is dependent on
0122         * the position of just one other edge. If a constraint is subsequently added
0123         * to create a new binding for an edge, the previous binding is discarded
0124         * and the edge remains dependent on a single edge. 
0125         * Springs should only be attached
0126         * between edges of the container and its immediate children; the behavior
0127         * of the <code>SpringLayout</code> when presented with constraints linking
0128         * the edges of components from different containers (either internal or
0129         * external) is undefined.
0130         *
0131         * <h3>
0132         * SpringLayout vs. Other Layout Managers
0133         * </h3>
0134         *
0135         * <blockquote>
0136         * <hr>
0137         * <strong>Note:</strong>
0138         * Unlike many layout managers,
0139         * <code>SpringLayout</code> doesn't automatically set the location of
0140         * the components it manages.
0141         * If you hand-code a GUI that uses <code>SpringLayout</code>, 
0142         * remember to initialize component locations by constraining the west/east
0143         * and north/south locations.
0144         * <p>
0145         * Depending on the constraints you use,
0146         * you may also need to set the size of the container explicitly.
0147         * <hr>
0148         * </blockquote>
0149         *
0150         * <p>
0151         * Despite the simplicity of <code>SpringLayout</code>,
0152         * it can emulate the behavior of most other layout managers.
0153         * For some features,
0154         * such as the line breaking provided by <code>FlowLayout</code>, 
0155         * you'll need to 
0156         * create a special-purpose subclass of the <code>Spring</code> class.
0157         *
0158         * <p>
0159         * <code>SpringLayout</code> also provides a way to solve
0160         * many of the difficult layout
0161         * problems that cannot be solved by nesting combinations
0162         * of <code>Box</code>es. That said, <code>SpringLayout</code> honors the
0163         * <code>LayoutManager2</code> contract correctly and so can be nested with
0164         * other layout managers -- a technique that can be preferable to
0165         * creating the constraints implied by the other layout managers.
0166         * <p>
0167         * The asymptotic complexity of the layout operation of a <code>SpringLayout</code>
0168         * is linear in the number of constraints (and/or components).
0169         * <p>
0170         * <strong>Warning:</strong>
0171         * Serialized objects of this class will not be compatible with
0172         * future Swing releases. The current serialization support is
0173         * appropriate for short term storage or RMI between applications running
0174         * the same version of Swing.  As of 1.4, support for long term storage
0175         * of all JavaBeans<sup><font size="-2">TM</font></sup>
0176         * has been added to the <code>java.beans</code> package.
0177         * Please see {@link java.beans.XMLEncoder}.
0178         *
0179         * @see Spring
0180         * @see SpringLayout.Constraints
0181         *
0182         * @version  1.32 05/05/07
0183         * @author 	Philip Milne
0184         * @author 	Scott Violet
0185         * @author 	Joe Winchester
0186         * @since       1.4
0187         */
0188        public class SpringLayout implements  LayoutManager2 {
0189            private Map componentConstraints = new HashMap();
0190
0191            private Spring cyclicReference = Spring.constant(Spring.UNSET);
0192            private Set cyclicSprings;
0193            private Set acyclicSprings;
0194
0195            /**
0196             * Specifies the top edge of a component's bounding rectangle.
0197             */
0198            public static final String NORTH = "North";
0199
0200            /**
0201             * Specifies the bottom edge of a component's bounding rectangle.
0202             */
0203            public static final String SOUTH = "South";
0204
0205            /**
0206             * Specifies the right edge of a component's bounding rectangle.
0207             */
0208            public static final String EAST = "East";
0209
0210            /**
0211             * Specifies the left edge of a component's bounding rectangle.
0212             */
0213            public static final String WEST = "West";
0214
0215            /**
0216             * Specifies the horizontal center of a component's bounding rectangle.
0217             *
0218             * @since 1.6
0219             */
0220            public static final String HORIZONTAL_CENTER = "HorizontalCenter";
0221
0222            /**
0223             * Specifies the vertical center of a component's bounding rectangle.
0224             *
0225             * @since 1.6
0226             */
0227            public static final String VERTICAL_CENTER = "VerticalCenter";
0228
0229            /**
0230             * Specifies the baseline of a component.
0231             *
0232             * @since 1.6
0233             */
0234            public static final String BASELINE = "Baseline";
0235
0236            /**
0237             * Specifies the width of a component's bounding rectangle.
0238             *
0239             * @since 1.6
0240             */
0241            public static final String WIDTH = "Width";
0242
0243            /**
0244             * Specifies the height of a component's bounding rectangle.
0245             *
0246             * @since 1.6
0247             */
0248            public static final String HEIGHT = "Height";
0249
0250            private static String[] ALL_HORIZONTAL = { WEST, WIDTH, EAST,
0251                    HORIZONTAL_CENTER };
0252
0253            private static String[] ALL_VERTICAL = { NORTH, HEIGHT, SOUTH,
0254                    VERTICAL_CENTER, BASELINE };
0255
0256            /**
0257             * A <code>Constraints</code> object holds the
0258             * constraints that govern the way a component's size and position
0259             * change in a container controlled by a <code>SpringLayout</code>.
0260             * A <code>Constraints</code> object is
0261             * like a <code>Rectangle</code>, in that it
0262             * has <code>x</code>, <code>y</code>,
0263             * <code>width</code>, and <code>height</code> properties.
0264             * In the <code>Constraints</code> object, however,
0265             * these properties have
0266             * <code>Spring</code> values instead of integers.
0267             * In addition,
0268             * a <code>Constraints</code> object
0269             * can be manipulated as four edges
0270             * -- north, south, east, and west --
0271             * using the <code>constraint</code> property.
0272             *
0273             * <p>
0274             * The following formulas are always true
0275             * for a <code>Constraints</code> object (here WEST and <code>x</code> are synonyms, as are and NORTH and <code>y</code>):
0276             *
0277             * <pre>
0278             *               EAST = WEST + WIDTH
0279             *              SOUTH = NORTH + HEIGHT
0280             *  HORIZONTAL_CENTER = WEST + WIDTH/2
0281             *    VERTICAL_CENTER = NORTH + HEIGHT/2
0282             *  ABSOLUTE_BASELINE = NORTH + RELATIVE_BASELINE*
0283             * </pre>
0284             * <p>
0285             * For example, if you have specified the WIDTH and WEST (X) location
0286             * the EAST is calculated as WEST + WIDTH.  If you instead specified
0287             * the WIDTH and EAST locations the WEST (X) location is then calculated
0288             * as EAST - WIDTH.
0289             * <p>
0290             * [RELATIVE_BASELINE is a private constraint that is set automatically when
0291             * the SpringLayout.Constraints(Component) constuctor is called or when
0292             * a constraints object is registered with a SpringLayout object.]
0293             * <p>
0294             * <b>Note</b>: In this document,
0295             * operators represent methods
0296             * in the <code>Spring</code> class.
0297             * For example, "a + b" is equal to
0298             * <code>Spring.sum(a, b)</code>,
0299             * and "a - b" is equal to
0300             * <code>Spring.sum(a, Spring.minus(b))</code>.
0301             * See the
0302             * {@link Spring <code>Spring</code> API documentation}
0303             * for further details
0304             * of spring arithmetic.
0305             *
0306             * <p>
0307             *
0308             * Because a <code>Constraints</code> object's properties --
0309             * representing its edges, size, and location -- can all be set
0310             * independently and yet are interrelated,
0311             * a <code>Constraints</code> object can become <em>over-constrained</em>.
0312             * For example, if the <code>WEST</code>, <code>WIDTH</code> and
0313             * <code>EAST</code> edges are all set, steps must be taken to ensure that
0314             * the first of the formulas above holds.  To do this, the
0315             * <code>Constraints</code>
0316             * object throws away the <em>least recently set</em>
0317             * constraint so as to make the formulas hold.
0318             * @since 1.4
0319             */
0320            public static class Constraints {
0321                private Spring x;
0322                private Spring y;
0323                private Spring width;
0324                private Spring height;
0325                private Spring east;
0326                private Spring south;
0327                private Spring horizontalCenter;
0328                private Spring verticalCenter;
0329                private Spring baseline;
0330
0331                private List<String> horizontalHistory = new ArrayList<String>(
0332                        2);
0333                private List<String> verticalHistory = new ArrayList<String>(2);
0334
0335                // Used for baseline calculations
0336                private Component c;
0337
0338                /**
0339                 * Creates an empty <code>Constraints</code> object.
0340                 */
0341                public Constraints() {
0342                }
0343
0344                /**
0345                 * Creates a <code>Constraints</code> object with the
0346                 * specified values for its
0347                 * <code>x</code> and <code>y</code> properties.
0348                 * The <code>height</code> and <code>width</code> springs
0349                 * have <code>null</code> values.
0350                 *
0351                 * @param x  the spring controlling the component's <em>x</em> value
0352                 * @param y  the spring controlling the component's <em>y</em> value
0353                 */
0354                public Constraints(Spring x, Spring y) {
0355                    setX(x);
0356                    setY(y);
0357                }
0358
0359                /**
0360                 * Creates a <code>Constraints</code> object with the 
0361                 * specified values for its
0362                 * <code>x</code>, <code>y</code>, <code>width</code>,
0363                 * and <code>height</code> properties.
0364                 * Note: If the <code>SpringLayout</code> class
0365                 * encounters <code>null</code> values in the
0366                 * <code>Constraints</code> object of a given component,
0367                 * it replaces them with suitable defaults.
0368                 *
0369                 * @param x  the spring value for the <code>x</code> property
0370                 * @param y  the spring value for the <code>y</code> property
0371                 * @param width  the spring value for the <code>width</code> property
0372                 * @param height  the spring value for the <code>height</code> property
0373                 */
0374                public Constraints(Spring x, Spring y, Spring width,
0375                        Spring height) {
0376                    setX(x);
0377                    setY(y);
0378                    setWidth(width);
0379                    setHeight(height);
0380                }
0381
0382                /**
0383                 * Creates a <code>Constraints</code> object with
0384                 * suitable <code>x</code>, <code>y</code>, <code>width</code> and
0385                 * <code>height</code> springs for component, <code>c</code>.
0386                 * The <code>x</code> and <code>y</code> springs are constant
0387                 * springs  initialised with the component's location at
0388                 * the time this method is called. The <code>width</code> and
0389                 * <code>height</code> springs are special springs, created by
0390                 * the <code>Spring.width()</code> and <code>Spring.height()</code>
0391                 * methods, which track the size characteristics of the component
0392                 * when they change.
0393                 *
0394                 * @param c  the component whose characteristics will be reflected by this Constraints object
0395                 * @throws NullPointerException if <code>c</code> is null.
0396                 * @since 1.5
0397                 */
0398                public Constraints(Component c) {
0399                    this .c = c;
0400                    setX(Spring.constant(c.getX()));
0401                    setY(Spring.constant(c.getY()));
0402                    setWidth(Spring.width(c));
0403                    setHeight(Spring.height(c));
0404                }
0405
0406                private void pushConstraint(String name, Spring value,
0407                        boolean horizontal) {
0408                    boolean valid = true;
0409                    List<String> history = horizontal ? horizontalHistory
0410                            : verticalHistory;
0411                    if (history.contains(name)) {
0412                        history.remove(name);
0413                        valid = false;
0414                    } else if (history.size() == 2 && value != null) {
0415                        history.remove(0);
0416                        valid = false;
0417                    }
0418                    if (value != null) {
0419                        history.add(name);
0420                    }
0421                    if (!valid) {
0422                        String[] all = horizontal ? ALL_HORIZONTAL
0423                                : ALL_VERTICAL;
0424                        for (int i = 0; i < all.length; i++) {
0425                            String s = all[i];
0426                            if (!history.contains(s)) {
0427                                setConstraint(s, null);
0428                            }
0429                        }
0430                    }
0431                }
0432
0433                private Spring sum(Spring s1, Spring s2) {
0434                    return (s1 == null || s2 == null) ? null : Spring.sum(s1,
0435                            s2);
0436                }
0437
0438                private Spring difference(Spring s1, Spring s2) {
0439                    return (s1 == null || s2 == null) ? null : Spring
0440                            .difference(s1, s2);
0441                }
0442
0443                private Spring scale(Spring s, float factor) {
0444                    return (s == null) ? null : Spring.scale(s, factor);
0445                }
0446
0447                private int getBaselineFromHeight(int height) {
0448                    if (height < 0) {
0449                        // Bad Scott, Bad Scott!
0450                        return -c.getBaseline(c.getPreferredSize().width,
0451                                -height);
0452                    }
0453                    return c.getBaseline(c.getPreferredSize().width, height);
0454                }
0455
0456                private int getHeightFromBaseLine(int baseline) {
0457                    Dimension prefSize = c.getPreferredSize();
0458                    int prefHeight = prefSize.height;
0459                    int prefBaseline = c
0460                            .getBaseline(prefSize.width, prefHeight);
0461                    if (prefBaseline == baseline) {
0462                        // If prefBaseline < 0, then no baseline, assume preferred
0463                        // height.
0464                        // If prefBaseline == baseline, then specified baseline
0465                        // matches preferred baseline, return preferred height
0466                        return prefHeight;
0467                    }
0468                    // Valid baseline
0469                    switch (c.getBaselineResizeBehavior()) {
0470                    case CONSTANT_DESCENT:
0471                        return prefHeight + (baseline - prefBaseline);
0472                    case CENTER_OFFSET:
0473                        return prefHeight + 2 * (baseline - prefBaseline);
0474                    case CONSTANT_ASCENT:
0475                        // Component baseline and specified baseline will NEVER
0476                        // match, fall through to default
0477                    default: // OTHER
0478                        // No way to map from baseline to height.
0479                    }
0480                    return Integer.MIN_VALUE;
0481                }
0482
0483                private Spring heightToRelativeBaseline(Spring s) {
0484                    return new Spring.SpringMap(s) {
0485                        protected int map(int i) {
0486                            return getBaselineFromHeight(i);
0487                        }
0488
0489                        protected int inv(int i) {
0490                            return getHeightFromBaseLine(i);
0491                        }
0492                    };
0493                }
0494
0495                private Spring relativeBaselineToHeight(Spring s) {
0496                    return new Spring.SpringMap(s) {
0497                        protected int map(int i) {
0498                            return getHeightFromBaseLine(i);
0499                        }
0500
0501                        protected int inv(int i) {
0502                            return getBaselineFromHeight(i);
0503                        }
0504                    };
0505                }
0506
0507                private boolean defined(List history, String s1, String s2) {
0508                    return history.contains(s1) && history.contains(s2);
0509                }
0510
0511                /**
0512                 * Sets the <code>x</code> property,
0513                 * which controls the <code>x</code> value
0514                 * of a component's location.
0515                 *
0516                 * @param x the spring controlling the <code>x</code> value
0517                 *          of a component's location
0518                 *
0519                 * @see #getX
0520                 * @see SpringLayout.Constraints
0521                 */
0522                public void setX(Spring x) {
0523                    this .x = x;
0524                    pushConstraint(WEST, x, true);
0525                }
0526
0527                /**
0528                 * Returns the value of the <code>x</code> property.
0529                 *
0530                 * @return the spring controlling the <code>x</code> value
0531                 *         of a component's location
0532                 *
0533                 * @see #setX
0534                 * @see SpringLayout.Constraints
0535                 */
0536                public Spring getX() {
0537                    if (x == null) {
0538                        if (defined(horizontalHistory, EAST, WIDTH)) {
0539                            x = difference(east, width);
0540                        } else if (defined(horizontalHistory,
0541                                HORIZONTAL_CENTER, WIDTH)) {
0542                            x = difference(horizontalCenter, scale(width, 0.5f));
0543                        } else if (defined(horizontalHistory,
0544                                HORIZONTAL_CENTER, EAST)) {
0545                            x = difference(scale(horizontalCenter, 2f), east);
0546                        }
0547                    }
0548                    return x;
0549                }
0550
0551                /**
0552                 * Sets the <code>y</code> property,
0553                 * which controls the <code>y</code> value
0554                 * of a component's location.
0555                 *
0556                 * @param y the spring controlling the <code>y</code> value
0557                 *          of a component's location
0558                 *
0559                 * @see #getY
0560                 * @see SpringLayout.Constraints
0561                 */
0562                public void setY(Spring y) {
0563                    this .y = y;
0564                    pushConstraint(NORTH, y, false);
0565                }
0566
0567                /**
0568                 * Returns the value of the <code>y</code> property.
0569                 *
0570                 * @return the spring controlling the <code>y</code> value
0571                 *         of a component's location
0572                 *
0573                 * @see #setY
0574                 * @see SpringLayout.Constraints
0575                 */
0576                public Spring getY() {
0577                    if (y == null) {
0578                        if (defined(verticalHistory, SOUTH, HEIGHT)) {
0579                            y = difference(south, height);
0580                        } else if (defined(verticalHistory, VERTICAL_CENTER,
0581                                HEIGHT)) {
0582                            y = difference(verticalCenter, scale(height, 0.5f));
0583                        } else if (defined(verticalHistory, VERTICAL_CENTER,
0584                                SOUTH)) {
0585                            y = difference(scale(verticalCenter, 2f), south);
0586                        } else if (defined(verticalHistory, BASELINE, HEIGHT)) {
0587                            y = difference(baseline,
0588                                    heightToRelativeBaseline(height));
0589                        } else if (defined(verticalHistory, BASELINE, SOUTH)) {
0590                            y = scale(difference(baseline,
0591                                    heightToRelativeBaseline(south)), 2f);
0592                            /*
0593                             } else if (defined(verticalHistory, BASELINE, VERTICAL_CENTER)) {
0594                             y = scale(difference(baseline, heightToRelativeBaseline(scale(verticalCenter, 2))), 1f/(1-2*0.5f)); 
0595                             */
0596                        }
0597                    }
0598                    return y;
0599                }
0600
0601                /**
0602                 * Sets the <code>width</code> property,
0603                 * which controls the width of a component.
0604                 *
0605                 * @param width the spring controlling the width of this
0606                 * <code>Constraints</code> object
0607                 *
0608                 * @see #getWidth
0609                 * @see SpringLayout.Constraints
0610                 */
0611                public void setWidth(Spring width) {
0612                    this .width = width;
0613                    pushConstraint(WIDTH, width, true);
0614                }
0615
0616                /**
0617                 * Returns the value of the <code>width</code> property.
0618                 *
0619                 * @return the spring controlling the width of a component
0620                 *
0621                 * @see #setWidth
0622                 * @see SpringLayout.Constraints
0623                 */
0624                public Spring getWidth() {
0625                    if (width == null) {
0626                        if (horizontalHistory.contains(EAST)) {
0627                            width = difference(east, getX());
0628                        } else if (horizontalHistory
0629                                .contains(HORIZONTAL_CENTER)) {
0630                            width = scale(difference(horizontalCenter, getX()),
0631                                    2f);
0632                        }
0633                    }
0634                    return width;
0635                }
0636
0637                /**
0638                 * Sets the <code>height</code> property,
0639                 * which controls the height of a component.
0640                 *
0641                 * @param height the spring controlling the height of this <code>Constraints</code>
0642                 * object
0643                 *
0644                 * @see #getHeight
0645                 * @see SpringLayout.Constraints
0646                 */
0647                public void setHeight(Spring height) {
0648                    this .height = height;
0649                    pushConstraint(HEIGHT, height, false);
0650                }
0651
0652                /**
0653                 * Returns the value of the <code>height</code> property.
0654                 *
0655                 * @return the spring controlling the height of a component
0656                 *
0657                 * @see #setHeight
0658                 * @see SpringLayout.Constraints
0659                 */
0660                public Spring getHeight() {
0661                    if (height == null) {
0662                        if (verticalHistory.contains(SOUTH)) {
0663                            height = difference(south, getY());
0664                        } else if (verticalHistory.contains(VERTICAL_CENTER)) {
0665                            height = scale(difference(verticalCenter, getY()),
0666                                    2f);
0667                        } else if (verticalHistory.contains(BASELINE)) {
0668                            height = relativeBaselineToHeight(difference(
0669                                    baseline, getY()));
0670                        }
0671                    }
0672                    return height;
0673                }
0674
0675                private void setEast(Spring east) {
0676                    this .east = east;
0677                    pushConstraint(EAST, east, true);
0678                }
0679
0680                private Spring getEast() {
0681                    if (east == null) {
0682                        east = sum(getX(), getWidth());
0683                    }
0684                    return east;
0685                }
0686
0687                private void setSouth(Spring south) {
0688                    this .south = south;
0689                    pushConstraint(SOUTH, south, false);
0690                }
0691
0692                private Spring getSouth() {
0693                    if (south == null) {
0694                        south = sum(getY(), getHeight());
0695                    }
0696                    return south;
0697                }
0698
0699                private Spring getHorizontalCenter() {
0700                    if (horizontalCenter == null) {
0701                        horizontalCenter = sum(getX(), scale(getWidth(), 0.5f));
0702                    }
0703                    return horizontalCenter;
0704                }
0705
0706                private void setHorizontalCenter(Spring horizontalCenter) {
0707                    this .horizontalCenter = horizontalCenter;
0708                    pushConstraint(HORIZONTAL_CENTER, horizontalCenter, true);
0709                }
0710
0711                private Spring getVerticalCenter() {
0712                    if (verticalCenter == null) {
0713                        verticalCenter = sum(getY(), scale(getHeight(), 0.5f));
0714                    }
0715                    return verticalCenter;
0716                }
0717
0718                private void setVerticalCenter(Spring verticalCenter) {
0719                    this .verticalCenter = verticalCenter;
0720                    pushConstraint(VERTICAL_CENTER, verticalCenter, false);
0721                }
0722
0723                private Spring getBaseline() {
0724                    if (baseline == null) {
0725                        baseline = sum(getY(),
0726                                heightToRelativeBaseline(getHeight()));
0727                    }
0728                    return baseline;
0729                }
0730
0731                private void setBaseline(Spring baseline) {
0732                    this .baseline = baseline;
0733                    pushConstraint(BASELINE, baseline, false);
0734                }
0735
0736                /**
0737                 * Sets the spring controlling the specified edge.
0738                 * The edge must have one of the following values:
0739                 * <code>SpringLayout.NORTH</code>, 
0740                 * <code>SpringLayout.SOUTH</code>,
0741                 * <code>SpringLayout.EAST</code>, 
0742                 * <code>SpringLayout.WEST</code>, 
0743                 * <code>SpringLayout.HORIZONTAL_CENTER</code>,
0744                 * <code>SpringLayout.VERTICAL_CENTER</code>, 
0745                 * <code>SpringLayout.BASELINE</code>, 
0746                 * <code>SpringLayout.WIDTH</code> or
0747                 * <code>SpringLayout.HEIGHT</code>. 
0748                 * For any other <code>String</code> value passed as the edge,
0749                 * no action is taken. For a <code>null</code> edge, a
0750                 * <code>NullPointerException</code> is thrown.
0751                 *
0752                 * @param edgeName the edge to be set
0753                 * @param s the spring controlling the specified edge
0754                 *
0755                 * @throws NullPointerException if <code>edgeName</code> is <code>null</code>
0756                 *
0757                 * @see #getConstraint
0758                 * @see #NORTH
0759                 * @see #SOUTH
0760                 * @see #EAST
0761                 * @see #WEST
0762                 * @see #HORIZONTAL_CENTER
0763                 * @see #VERTICAL_CENTER
0764                 * @see #BASELINE
0765                 * @see #WIDTH
0766                 * @see #HEIGHT
0767                 * @see SpringLayout.Constraints
0768                 */
0769                public void setConstraint(String edgeName, Spring s) {
0770                    edgeName = edgeName.intern();
0771                    if (edgeName == WEST) {
0772                        setX(s);
0773                    } else if (edgeName == NORTH) {
0774                        setY(s);
0775                    } else if (edgeName == EAST) {
0776                        setEast(s);
0777                    } else if (edgeName == SOUTH) {
0778                        setSouth(s);
0779                    } else if (edgeName == HORIZONTAL_CENTER) {
0780                        setHorizontalCenter(s);
0781                    } else if (edgeName == WIDTH) {
0782                        setWidth(s);
0783                    } else if (edgeName == HEIGHT) {
0784                        setHeight(s);
0785                    } else if (edgeName == VERTICAL_CENTER) {
0786                        setVerticalCenter(s);
0787                    } else if (edgeName == BASELINE) {
0788                        setBaseline(s);
0789                    }
0790                }
0791
0792                /**
0793                 * Returns the value of the specified edge, which may be
0794                 * a derived value, or even <code>null</code>.
0795                 * The edge must have one of the following values:
0796                 * <code>SpringLayout.NORTH</code>, 
0797                 * <code>SpringLayout.SOUTH</code>,
0798                 * <code>SpringLayout.EAST</code>, 
0799                 * <code>SpringLayout.WEST</code>, 
0800                 * <code>SpringLayout.HORIZONTAL_CENTER</code>,
0801                 * <code>SpringLayout.VERTICAL_CENTER</code>, 
0802                 * <code>SpringLayout.BASELINE</code>, 
0803                 * <code>SpringLayout.WIDTH</code> or
0804                 * <code>SpringLayout.HEIGHT</code>. 
0805                 * For any other <code>String</code> value passed as the edge,
0806                 * <code>null</code> will be returned. Throws
0807                 * <code>NullPointerException</code> for a <code>null</code> edge.
0808                 *
0809                 * @param edgeName the edge whose value
0810                 *                 is to be returned
0811                 *
0812                 * @return the spring controlling the specified edge, may be <code>null</code>
0813                 *
0814                 * @throws NullPointerException if <code>edgeName</code> is <code>null</code>
0815                 *
0816                 * @see #setConstraint
0817                 * @see #NORTH
0818                 * @see #SOUTH
0819                 * @see #EAST
0820                 * @see #WEST
0821                 * @see #HORIZONTAL_CENTER
0822                 * @see #VERTICAL_CENTER
0823                 * @see #BASELINE
0824                 * @see #WIDTH
0825                 * @see #HEIGHT
0826                 * @see SpringLayout.Constraints
0827                 */
0828                public Spring getConstraint(String edgeName) {
0829                    edgeName = edgeName.intern();
0830                    return (edgeName == WEST) ? getX()
0831                            : (edgeName == NORTH) ? getY()
0832                                    : (edgeName == EAST) ? getEast()
0833                                            : (edgeName == SOUTH) ? getSouth()
0834                                                    : (edgeName == WIDTH) ? getWidth()
0835                                                            : (edgeName == HEIGHT) ? getHeight()
0836                                                                    : (edgeName == HORIZONTAL_CENTER) ? getHorizontalCenter()
0837                                                                            : (edgeName == VERTICAL_CENTER) ? getVerticalCenter()
0838                                                                                    : (edgeName == BASELINE) ? getBaseline()
0839                                                                                            : null;
0840                }
0841
0842                /*pp*/void reset() {
0843                    Spring[] allSprings = { x, y, width, height, east, south,
0844                            horizontalCenter, verticalCenter, baseline };
0845                    for (int i = 0; i < allSprings.length; i++) {
0846                        Spring s = allSprings[i];
0847                        if (s != null) {
0848                            s.setValue(Spring.UNSET);
0849                        }
0850                    }
0851                }
0852            }
0853
0854            private static class SpringProxy extends Spring {
0855                private String edgeName;
0856                private Component c;
0857                private SpringLayout l;
0858
0859                public SpringProxy(String edgeName, Component c, SpringLayout l) {
0860                    this .edgeName = edgeName;
0861                    this .c = c;
0862                    this .l = l;
0863                }
0864
0865                private Spring getConstraint() {
0866                    return l.getConstraints(c).getConstraint(edgeName);
0867                }
0868
0869                public int getMinimumValue() {
0870                    return getConstraint().getMinimumValue();
0871                }
0872
0873                public int getPreferredValue() {
0874                    return getConstraint().getPreferredValue();
0875                }
0876
0877                public int getMaximumValue() {
0878                    return getConstraint().getMaximumValue();
0879                }
0880
0881                public int getValue() {
0882                    return getConstraint().getValue();
0883                }
0884
0885                public void setValue(int size) {
0886                    getConstraint().setValue(size);
0887                }
0888
0889                /*pp*/boolean isCyclic(SpringLayout l) {
0890                    return l.isCyclic(getConstraint());
0891                }
0892
0893                public String toString() {
0894                    return "SpringProxy for " + edgeName + " edge of "
0895                            + c.getName() + ".";
0896                }
0897            }
0898
0899            /**
0900             * Constructs a new <code>SpringLayout</code>.
0901             */
0902            public SpringLayout() {
0903            }
0904
0905            private void resetCyclicStatuses() {
0906                cyclicSprings = new HashSet();
0907                acyclicSprings = new HashSet();
0908            }
0909
0910            private void setParent(Container p) {
0911                resetCyclicStatuses();
0912                Constraints pc = getConstraints(p);
0913
0914                pc.setX(Spring.constant(0));
0915                pc.setY(Spring.constant(0));
0916                // The applyDefaults() method automatically adds width and
0917                // height springs that delegate their calculations to the
0918                // getMinimumSize(), getPreferredSize() and getMaximumSize()
0919                // methods of the relevant component. In the case of the
0920                // parent this will cause an infinite loop since these
0921                // methods, in turn, delegate their calculations to the
0922                // layout manager. Check for this case and replace the
0923                // the springs that would cause this problem with a
0924                // constant springs that supply default values.
0925                Spring width = pc.getWidth();
0926                if (width instanceof  Spring.WidthSpring
0927                        && ((Spring.WidthSpring) width).c == p) {
0928                    pc.setWidth(Spring.constant(0, 0, Integer.MAX_VALUE));
0929                }
0930                Spring height = pc.getHeight();
0931                if (height instanceof  Spring.HeightSpring
0932                        && ((Spring.HeightSpring) height).c == p) {
0933                    pc.setHeight(Spring.constant(0, 0, Integer.MAX_VALUE));
0934                }
0935            }
0936
0937            /*pp*/boolean isCyclic(Spring s) {
0938                if (s == null) {
0939                    return false;
0940                }
0941                if (cyclicSprings.contains(s)) {
0942                    return true;
0943                }
0944                if (acyclicSprings.contains(s)) {
0945                    return false;
0946                }
0947                cyclicSprings.add(s);
0948                boolean result = s.isCyclic(this );
0949                if (!result) {
0950                    acyclicSprings.add(s);
0951                    cyclicSprings.remove(s);
0952                } else {
0953                    System.err.println(s + " is cyclic. ");
0954                }
0955                return result;
0956            }
0957
0958            private Spring abandonCycles(Spring s) {
0959                return isCyclic(s) ? cyclicReference : s;
0960            }
0961
0962            // LayoutManager methods.
0963
0964            /**
0965             * Has no effect,
0966             * since this layout manager does not
0967             * use a per-component string.
0968             */
0969            public void addLayoutComponent(String name, Component c) {
0970            }
0971
0972            /**
0973             * Removes the constraints associated with the specified component.
0974             *
0975             * @param c the component being removed from the container
0976             */
0977            public void removeLayoutComponent(Component c) {
0978                componentConstraints.remove(c);
0979            }
0980
0981            private static Dimension addInsets(int width, int height,
0982                    Container p) {
0983                Insets i = p.getInsets();
0984                return new Dimension(width + i.left + i.right, height + i.top
0985                        + i.bottom);
0986            }
0987
0988            public Dimension minimumLayoutSize(Container parent) {
0989                setParent(parent);
0990                Constraints pc = getConstraints(parent);
0991                return addInsets(
0992                        abandonCycles(pc.getWidth()).getMinimumValue(),
0993                        abandonCycles(pc.getHeight()).getMinimumValue(), parent);
0994            }
0995
0996            public Dimension preferredLayoutSize(Container parent) {
0997                setParent(parent);
0998                Constraints pc = getConstraints(parent);
0999                return addInsets(abandonCycles(pc.getWidth())
1000                        .getPreferredValue(), abandonCycles(pc.getHeight())
1001                        .getPreferredValue(), parent);
1002            }
1003
1004            // LayoutManager2 methods.
1005
1006            public Dimension maximumLayoutSize(Container parent) {
1007                setParent(parent);
1008                Constraints pc = getConstraints(parent);
1009                return addInsets(
1010                        abandonCycles(pc.getWidth()).getMaximumValue(),
1011                        abandonCycles(pc.getHeight()).getMaximumValue(), parent);
1012            }
1013
1014            /**
1015             * If <code>constraints</code> is an instance of 
1016             * <code>SpringLayout.Constraints</code>,
1017             * associates the constraints with the specified component.
1018             * <p>
1019             * @param   component the component being added
1020             * @param   constraints the component's constraints
1021             *
1022             * @see SpringLayout.Constraints
1023             */
1024            public void addLayoutComponent(Component component,
1025                    Object constraints) {
1026                if (constraints instanceof  Constraints) {
1027                    putConstraints(component, (Constraints) constraints);
1028                }
1029            }
1030
1031            /**
1032             * Returns 0.5f (centered).
1033             */
1034            public float getLayoutAlignmentX(Container p) {
1035                return 0.5f;
1036            }
1037
1038            /**
1039             * Returns 0.5f (centered).
1040             */
1041            public float getLayoutAlignmentY(Container p) {
1042                return 0.5f;
1043            }
1044
1045            public void invalidateLayout(Container p) {
1046            }
1047
1048            // End of LayoutManger2 methods
1049
1050            /**
1051             * Links edge <code>e1</code> of component <code>c1</code> to
1052             * edge <code>e2</code> of component <code>c2</code>,
1053             * with a fixed distance between the edges. This
1054             * constraint will cause the assignment
1055             * <pre>
1056             *     value(e1, c1) = value(e2, c2) + pad</pre>
1057             * to take place during all subsequent layout operations.
1058             * <p>
1059             * @param   e1 the edge of the dependent
1060             * @param   c1 the component of the dependent
1061             * @param   pad the fixed distance between dependent and anchor
1062             * @param   e2 the edge of the anchor
1063             * @param   c2 the component of the anchor
1064             *
1065             * @see #putConstraint(String, Component, Spring, String, Component)
1066             */
1067            public void putConstraint(String e1, Component c1, int pad,
1068                    String e2, Component c2) {
1069                putConstraint(e1, c1, Spring.constant(pad), e2, c2);
1070            }
1071
1072            /**
1073             * Links edge <code>e1</code> of component <code>c1</code> to
1074             * edge <code>e2</code> of component <code>c2</code>. As edge
1075             * <code>(e2, c2)</code> changes value, edge <code>(e1, c1)</code> will
1076             * be calculated by taking the (spring) sum of <code>(e2, c2)</code>
1077             * and <code>s</code>.
1078             * Each edge must have one of the following values:
1079             * <code>SpringLayout.NORTH</code>, 
1080             * <code>SpringLayout.SOUTH</code>,
1081             * <code>SpringLayout.EAST</code>, 
1082             * <code>SpringLayout.WEST</code>,
1083             * <code>SpringLayout.VERTICAL_CENTER</code>, 
1084             * <code>SpringLayout.HORIZONTAL_CENTER</code> or
1085             * <code>SpringLayout.BASELINE</code>.
1086             * <p>
1087             * @param   e1 the edge of the dependent
1088             * @param   c1 the component of the dependent
1089             * @param   s the spring linking dependent and anchor
1090             * @param   e2 the edge of the anchor
1091             * @param   c2 the component of the anchor
1092             *
1093             * @see #putConstraint(String, Component, int, String, Component)
1094             * @see #NORTH
1095             * @see #SOUTH
1096             * @see #EAST
1097             * @see #WEST
1098             * @see #VERTICAL_CENTER
1099             * @see #HORIZONTAL_CENTER
1100             * @see #BASELINE
1101             */
1102            public void putConstraint(String e1, Component c1, Spring s,
1103                    String e2, Component c2) {
1104                putConstraint(e1, c1, Spring.sum(s, getConstraint(e2, c2)));
1105            }
1106
1107            private void putConstraint(String e, Component c, Spring s) {
1108                if (s != null) {
1109                    getConstraints(c).setConstraint(e, s);
1110                }
1111            }
1112
1113            private Constraints applyDefaults(Component c,
1114                    Constraints constraints) {
1115                if (constraints == null) {
1116                    constraints = new Constraints();
1117                }
1118                if (constraints.c == null) {
1119                    constraints.c = c;
1120                }
1121                if (constraints.horizontalHistory.size() < 2) {
1122                    applyDefaults(constraints, WEST, Spring.constant(0), WIDTH,
1123                            Spring.width(c), constraints.horizontalHistory);
1124                }
1125                if (constraints.verticalHistory.size() < 2) {
1126                    applyDefaults(constraints, NORTH, Spring.constant(0),
1127                            HEIGHT, Spring.height(c),
1128                            constraints.verticalHistory);
1129                }
1130                return constraints;
1131            }
1132
1133            private void applyDefaults(Constraints constraints, String name1,
1134                    Spring spring1, String name2, Spring spring2,
1135                    List<String> history) {
1136                if (history.size() == 0) {
1137                    constraints.setConstraint(name1, spring1);
1138                    constraints.setConstraint(name2, spring2);
1139                } else {
1140                    // At this point there must be exactly one constraint defined already.
1141                    // Check width/height first. 
1142                    if (constraints.getConstraint(name2) == null) {
1143                        constraints.setConstraint(name2, spring2);
1144                    } else {
1145                        // If width/height is already defined, install a default for x/y.
1146                        constraints.setConstraint(name1, spring1);
1147                    }
1148                    // Either way, leave the user's constraint topmost on the stack. 
1149                    Collections.rotate(history, 1);
1150                }
1151            }
1152
1153            private void putConstraints(Component component,
1154                    Constraints constraints) {
1155                componentConstraints.put(component, applyDefaults(component,
1156                        constraints));
1157            }
1158
1159            /**
1160             * Returns the constraints for the specified component.
1161             * Note that,
1162             * unlike the <code>GridBagLayout</code>
1163             * <code>getConstraints</code> method,
1164             * this method does not clone constraints.
1165             * If no constraints
1166             * have been associated with this component,
1167             * this method
1168             * returns a default constraints object positioned at
1169             * 0,0 relative to the parent's Insets and its width/height
1170             * constrained to the minimum, maximum, and preferred sizes of the
1171             * component. The size characteristics
1172             * are not frozen at the time this method is called;
1173             * instead this method returns a constraints object
1174             * whose characteristics track the characteristics
1175             * of the component as they change.
1176             *
1177             * @param       c the component whose constraints will be returned
1178             *
1179             * @return      the constraints for the specified component
1180             */
1181            public Constraints getConstraints(Component c) {
1182                Constraints result = (Constraints) componentConstraints.get(c);
1183                if (result == null) {
1184                    if (c instanceof  javax.swing.JComponent) {
1185                        Object cp = ((javax.swing.JComponent) c)
1186                                .getClientProperty(SpringLayout.class);
1187                        if (cp instanceof  Constraints) {
1188                            return applyDefaults(c, (Constraints) cp);
1189                        }
1190                    }
1191                    result = new Constraints();
1192                    putConstraints(c, result);
1193                }
1194                return result;
1195            }
1196
1197            /**
1198             * Returns the spring controlling the distance between 
1199             * the specified edge of
1200             * the component and the top or left edge of its parent. This
1201             * method, instead of returning the current binding for the
1202             * edge, returns a proxy that tracks the characteristics
1203             * of the edge even if the edge is subsequently rebound.
1204             * Proxies are intended to be used in builder envonments
1205             * where it is useful to allow the user to define the
1206             * constraints for a layout in any order. Proxies do, however,
1207             * provide the means to create cyclic dependencies amongst
1208             * the constraints of a layout. Such cycles are detected
1209             * internally by <code>SpringLayout</code> so that
1210             * the layout operation always terminates.
1211             *
1212             * @param edgeName must be one of
1213             * <code>SpringLayout.NORTH</code>, 
1214             * <code>SpringLayout.SOUTH</code>,
1215             * <code>SpringLayout.EAST</code>, 
1216             * <code>SpringLayout.WEST</code>,
1217             * <code>SpringLayout.VERTICAL_CENTER</code>, 
1218             * <code>SpringLayout.HORIZONTAL_CENTER</code> or
1219             * <code>SpringLayout.BASELINE</code>
1220             * @param c the component whose edge spring is desired
1221             *
1222             * @return a proxy for the spring controlling the distance between the
1223             *         specified edge and the top or left edge of its parent
1224             * 
1225             * @see #NORTH
1226             * @see #SOUTH
1227             * @see #EAST
1228             * @see #WEST
1229             * @see #VERTICAL_CENTER
1230             * @see #HORIZONTAL_CENTER
1231             * @see #BASELINE
1232             */
1233            public Spring getConstraint(String edgeName, Component c) {
1234                // The interning here is unnecessary; it was added for efficiency.
1235                edgeName = edgeName.intern();
1236                return new SpringProxy(edgeName, c, this );
1237            }
1238
1239            public void layoutContainer(Container parent) {
1240                setParent(parent);
1241
1242                int n = parent.getComponentCount();
1243                getConstraints(parent).reset();
1244                for (int i = 0; i < n; i++) {
1245                    getConstraints(parent.getComponent(i)).reset();
1246                }
1247
1248                Insets insets = parent.getInsets();
1249                Constraints pc = getConstraints(parent);
1250                abandonCycles(pc.getX()).setValue(0);
1251                abandonCycles(pc.getY()).setValue(0);
1252                abandonCycles(pc.getWidth()).setValue(
1253                        parent.getWidth() - insets.left - insets.right);
1254                abandonCycles(pc.getHeight()).setValue(
1255                        parent.getHeight() - insets.top - insets.bottom);
1256
1257                for (int i = 0; i < n; i++) {
1258                    Component c = parent.getComponent(i);
1259                    Constraints cc = getConstraints(c);
1260                    int x = abandonCycles(cc.getX()).getValue();
1261                    int y = abandonCycles(cc.getY()).getValue();
1262                    int width = abandonCycles(cc.getWidth()).getValue();
1263                    int height = abandonCycles(cc.getHeight()).getValue();
1264                    c.setBounds(insets.left + x, insets.top + y, width, height);
1265                }
1266            }
1267        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.