diff options
Diffstat (limited to 'prototypes/miglayout/net/miginfocom/layout')
18 files changed, 10389 insertions, 10389 deletions
diff --git a/prototypes/miglayout/net/miginfocom/layout/AC.java b/prototypes/miglayout/net/miginfocom/layout/AC.java index 34ade72b..fe1e35bf 100644 --- a/prototypes/miglayout/net/miginfocom/layout/AC.java +++ b/prototypes/miglayout/net/miginfocom/layout/AC.java @@ -1,493 +1,493 @@ -package net.miginfocom.layout;
-
-import java.io.*;
-import java.util.ArrayList;
-
-/*
- * License (BSD):
- * ==============
- *
- * Copyright (c) 2004, Mikael Grev, MiG InfoCom AB. (miglayout (at) miginfocom (dot) com)
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification,
- * are permitted provided that the following conditions are met:
- * Redistributions of source code must retain the above copyright notice, this list
- * of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above copyright notice, this
- * list of conditions and the following disclaimer in the documentation and/or other
- * materials provided with the distribution.
- * Neither the name of the MiG InfoCom AB nor the names of its contributors may be
- * used to endorse or promote products derived from this software without specific
- * prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
- * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
- * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
- * OF SUCH DAMAGE.
- *
- * @version 1.0
- * @author Mikael Grev, MiG InfoCom AB
- * Date: 2006-sep-08
- */
-
-/** A constraint that holds the column <b>or</b> row constraints for the grid. It also holds the gaps between the rows and columns.
- * <p>
- * This class is a holder and builder for a number of {@link net.miginfocom.layout.DimConstraint}s.
- * <p>
- * For a more thorough explanation of what these constraints do, and how to build the constriants, see the White Paper or Cheat Sheet at www.migcomponents.com.
- * <p>
- * Note that there are two way to build this constraint. Through String (e.g. <code>"[100]3[200,fill]"</code> or through API (E.g.
- * <code>new AxisConstraint().size("100").gap("3").size("200").fill()</code>.
- */
-public final class AC implements Externalizable
-{
- private final ArrayList<DimConstraint> cList = new ArrayList<DimConstraint>(8);
-
- private transient int curIx = 0;
-
- /** Constructor. Creates an instance that can be configured manually. Will be initialized with a default
- * {@link net.miginfocom.layout.DimConstraint}.
- */
- public AC()
- {
- cList.add(new DimConstraint());
- }
-
- /** Property. The different {@link net.miginfocom.layout.DimConstraint}s that this object consists of.
- * These <code><DimConstraints/code> contains all information in this class.
- * @return The different {@link net.miginfocom.layout.DimConstraint}s that this object consists of. A new list and
- * never <code>null</code>.
- */
- public final DimConstraint[] getConstaints()
- {
- return cList.toArray(new DimConstraint[cList.size()]);
- }
-
- /** Sets the different {@link net.miginfocom.layout.DimConstraint}s that this object should consists of.
- * @param constr The different {@link net.miginfocom.layout.DimConstraint}s that this object consists of. The list
- * will be copied for storage. <code>null</code> or and emty array will reset the constaints to one <code>DimConstraint</code>
- * with default values.
- */
- public final void setConstaints(DimConstraint[] constr)
- {
- if (constr == null || constr.length < 1 )
- constr = new DimConstraint[] {new DimConstraint()};
-
- cList.clear();
- cList.ensureCapacity(constr.length);
- for (int i = 0; i < constr.length; i++)
- cList.add(constr[i]);
- }
-
- /** Returns the number of rows/columns that this constraints currently have.
- * @return The number of rows/columns that this constraints currently have. At least 1.
- */
- public int getCount()
- {
- return cList.size();
- }
-
- /** Sets the total number of rows/columns to <code>size</code>. If the number of rows/columns is already more
- * than <code>size</code> nothing will happen.
- * @param size The total number of rows/columns
- * @return <code>this</code> so it is possible to chain calls. E.g. <code>new AxisConstraint().noGrid().gap().fill()</code>.
- */
- public final AC count(int size)
- {
- makeSize(size);
- return this;
- }
-
- /** Specifies that the current row/column should not be grid-like. The while row/colum will have its components layed out
- * in one single cell. It is the same as to say that the cells in this column/row will all be merged (a.k.a spanned).
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @return <code>this</code> so it is possible to chain calls. E.g. <code>new AxisConstraint().noGrid().gap().fill()</code>.
- */
- public final AC noGrid()
- {
- return noGrid(curIx);
- }
-
- /** Specifies that the indicated rows/columns should not be grid-like. The while row/colum will have its components layed out
- * in one single cell. It is the same as to say that the cells in this column/row will all be merged (a.k.a spanned).
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @param indexes The index(es) (0-based) of the columns/rows that should be affected by this constraint.
- * @return <code>this</code> so it is possible to chain calls. E.g. <code>new AxisConstraint().noGrid().gap().fill()</code>.
- */
- public final AC noGrid(int... indexes)
- {
- for (int i = indexes.length - 1; i >= 0; i--) {
- int ix = indexes[i];
- makeSize(ix);
- cList.get(ix).setNoGrid(true);
- }
- return this;
- }
-
- /** Sets the current row/column to <code>i</code>. If the current number of rows/columns is less than <code>i</code> a call
- * to {@link #count(int)} will set the size accoringly.
- * <p>
- * The next call to any of the constriant methods (e.g. {@link net.miginfocom.layout.AC#noGrid}) will be carried
- * out on this new row/column.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @param i The new current row/column.
- * @return <code>this</code> so it is possible to chain calls. E.g. <code>new AxisConstraint().noGrid().gap().fill()</code>.
- */
- public final AC index(int i)
- {
- makeSize(i);
- curIx = i;
- return this;
- }
-
- /** Specifies that the current row/column's component should grow by default. It does not affect the size of the row/column.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @return <code>this</code> so it is possible to chain calls. E.g. <code>new AxisConstraint().noGrid().gap().fill()</code>.
- */
- public final AC fill()
- {
- return fill(curIx);
- }
-
- /** Specifies that the indicated rows'/columns' component should grow by default. It does not affect the size of the row/column.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @param indexes The index(es) (0-based) of the columns/rows that should be affected by this constraint.
- * @return <code>this</code> so it is possible to chain calls. E.g. <code>new AxisConstraint().noGrid().gap().fill()</code>.
- */
- public final AC fill(int... indexes)
- {
- for (int i = indexes.length - 1; i >= 0; i--) {
- int ix = indexes[i];
- makeSize(ix);
- cList.get(ix).setFill(true);
- }
- return this;
- }
-
-// /** Specifies that the current row/column should be put in the end group <code>s</code> and will thus share the same ending
-// * coordinate within the group.
-// * <p>
-// * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
-// * @param s A name to associate on the group that should be the same for other rows/columns in the same group.
-// * @return <code>this</code> so it is possible to chain calls. E.g. <code>new AxisConstraint().noGrid().gap().fill()</code>.
-// */
-// public final AxisConstraint endGroup(String s)
-// {
-// return endGroup(s, curIx);
-// }
-//
-// /** Specifies that the indicated rows/columns should be put in the end group <code>s</code> and will thus share the same ending
-// * coordinate within the group.
-// * <p>
-// * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
-// * @param s A name to associate on the group that should be the same for other rows/columns in the same group.
-// * @param indexes The index(es) (0-based) of the columns/rows that should be affected by this constraint.
-// * @return <code>this</code> so it is possible to chain calls. E.g. <code>new AxisConstraint().noGrid().gap().fill()</code>.
-// */
-// public final AxisConstraint endGroup(String s, int... indexes)
-// {
-// for (int i = indexes.length - 1; i >= 0; i--) {
-// int ix = indexes[i];
-// makeSize(ix);
-// cList.get(ix).setEndGroup(s);
-// }
-// return this;
-// }
-
- /** Specifies that the current row/column should be put in the size group <code>s</code> and will thus share the same size
- * constraints as the other components in the group.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @param s A name to associate on the group that should be the same for other rows/columns in the same group.
- * @return <code>this</code> so it is possible to chain calls. E.g. <code>new AxisConstraint().noGrid().gap().fill()</code>.
- */
- public final AC sizeGroup(String s)
- {
- return sizeGroup(s, curIx);
- }
-
- /** Specifies that the indicated rows/columns should be put in the size group <code>s</code> and will thus share the same size
- * constraints as the other components in the group.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @param s A name to associate on the group that should be the same for other rows/columns in the same group.
- * @param indexes The index(es) (0-based) of the columns/rows that should be affected by this constraint.
- * @return <code>this</code> so it is possible to chain calls. E.g. <code>new AxisConstraint().noGrid().gap().fill()</code>.
- */
- public final AC sizeGroup(String s, int... indexes)
- {
- for (int i = indexes.length - 1; i >= 0; i--) {
- int ix = indexes[i];
- makeSize(ix);
- cList.get(ix).setSizeGroup(s);
- }
- return this;
- }
-
- /** Specifies the current row/column's min and/or preferred and/or max size. E.g. <code>"10px"</code> or <code>"50:100:200"</code>.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @param s The minimum and/or preferred and/or maximum size of this row. The string will be interpreted
- * as a <b>BoundSize</b>. For more info on how <b>BoundSize</b> is formatted see the documentation.
- * @return <code>this</code> so it is possible to chain calls. E.g. <code>new AxisConstraint().noGrid().gap().fill()</code>.
- */
- public final AC size(String s)
- {
- return size(s, curIx);
- }
-
- /** Specifies the indicated rows'/columns' min and/or preferred and/or max size. E.g. <code>"10px"</code> or <code>"50:100:200"</code>.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @param size The minimum and/or preferred and/or maximum size of this row. The string will be interpreted
- * as a <b>BoundSize</b>. For more info on how <b>BoundSize</b> is formatted see the documentation.
- * @param indexes The index(es) (0-based) of the columns/rows that should be affected by this constraint.
- * @return <code>this</code> so it is possible to chain calls. E.g. <code>new AxisConstraint().noGrid().gap().fill()</code>.
- */
- public final AC size(String size, int... indexes)
- {
- BoundSize bs = ConstraintParser.parseBoundSize(size, false, true);
- for (int i = indexes.length - 1; i >= 0; i--) {
- int ix = indexes[i];
- makeSize(ix);
- cList.get(ix).setSize(bs);
- }
- return this;
- }
-
- /** Specifies the gap size to be the default one <b>AND</b> moves to the next column/row. The method is called <code>.gap()</code>
- * rather the more natural <code>.next()</code> to indicate that it is very much related to the other <code>.gap(..)</code> methods.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @return <code>this</code> so it is possible to chain calls. E.g. <code>new AxisConstraint().noGrid().gap().fill()</code>.
- */
- public final AC gap()
- {
- curIx++;
- return this;
- }
-
- /** Specifies the gap size to <code>size</code> <b>AND</b> moves to the next column/row.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @param size minimum and/or preferred and/or maximum size of the gap between this and the next row/column.
- * The string will be interpreted as a <b>BoundSize</b>. For more info on how <b>BoundSize</b> is formatted see the documentation.
- * @return <code>this</code> so it is possible to chain calls. E.g. <code>new AxisConstraint().noGrid().gap().fill()</code>.
- */
- public final AC gap(String size)
- {
- return gap(size, curIx++);
- }
-
- /** Specifies the indicated rows'/columns' gap size to <code>size</code>.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @param size minimum and/or preferred and/or maximum size of the gap between this and the next row/column.
- * The string will be interpreted as a <b>BoundSize</b>. For more info on how <b>BoundSize</b> is formatted see the documentation.
- * @param indexes The index(es) (0-based) of the columns/rows that should be affected by this constraint.
- * @return <code>this</code> so it is possible to chain calls. E.g. <code>new AxisConstraint().noGrid().gap().fill()</code>.
- */
- public final AC gap(String size, int... indexes)
- {
- BoundSize bsa = size != null ? ConstraintParser.parseBoundSize(size, true, true) : null;
-
- for (int i = indexes.length - 1; i >= 0; i--) {
- int ix = indexes[i];
- makeSize(ix);
- if (bsa != null)
- cList.get(ix).setGapAfter(bsa);
- }
- return this;
- }
-
- /** Specifies the current row/column's columns default alignment <b>for its components</b>. It does not affect the positioning
- * or size of the columns/row itself. For columns it is the horizonal alignment (e.g. "left") and for rows it is the vertical
- * alignment (e.g. "top").
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @param side The default side to align the components. E.g. "top" or "left", or "leading" or "trailing" or "bottom" or "right".
- * @return <code>this</code> so it is possible to chain calls. E.g. <code>new AxisConstraint().noGrid().gap().fill()</code>.
- */
- public final AC align(String side)
- {
- return align(side, curIx);
- }
-
- /** Specifies the indicated rows'/columns' columns default alignment <b>for its components</b>. It does not affect the positioning
- * or size of the columns/row itself. For columns it is the horizonal alignment (e.g. "left") and for rows it is the vertical
- * alignment (e.g. "top").
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @param side The default side to align the components. E.g. "top" or "left", or "before" or "after" or "bottom" or "right".
- * @param indexes The index(es) (0-based) of the columns/rows that should be affected by this constraint.
- * @return <code>this</code> so it is possible to chain calls. E.g. <code>new AxisConstraint().noGrid().gap().fill()</code>.
- */
- public final AC align(String side, int... indexes)
- {
- UnitValue al = ConstraintParser.parseAlignKeywords(side, true);
- if (al == null)
- al = ConstraintParser.parseAlignKeywords(side, false);
-
- for (int i = indexes.length - 1; i >= 0; i--) {
- int ix = indexes[i];
- makeSize(ix);
- cList.get(ix).setAlign(al);
- }
- return this;
- }
-
- /** Specifies the current row/column's grow priority.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @param p The new grow priority.
- * @return <code>this</code> so it is possible to chain calls. E.g. <code>new AxisConstraint().noGrid().gap().fill()</code>.
- */
- public final AC growPrio(int p)
- {
- return growPrio(p, curIx);
- }
-
- /** Specifies the indicated rows'/columns' grow priority.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @param p The new grow priority.
- * @param indexes The index(es) (0-based) of the columns/rows that should be affected by this constraint.
- * @return <code>this</code> so it is possible to chain calls. E.g. <code>new AxisConstraint().noGrid().gap().fill()</code>.
- */
- public final AC growPrio(int p, int... indexes)
- {
- for (int i = indexes.length - 1; i >= 0; i--) {
- int ix = indexes[i];
- makeSize(ix);
- cList.get(ix).setGrowPriority(p);
- }
- return this;
- }
-
- /** Specifies the current row/column's grow weight within columns/rows with the same <code>grow priority</code>.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @param w The new grow weight.
- * @return <code>this</code> so it is possible to chain calls. E.g. <code>new AxisConstraint().noGrid().gap().fill()</code>.
- */
- public final AC grow(float w)
- {
- return grow(w, curIx);
- }
-
- /** Specifies the indicated rows'/columns' grow weight within columns/rows with the same <code>grow priority</code>.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @param w The new grow weight.
- * @param indexes The index(es) (0-based) of the columns/rows that should be affected by this constraint.
- * @return <code>this</code> so it is possible to chain calls. E.g. <code>new AxisConstraint().noGrid().gap().fill()</code>.
- */
- public final AC grow(float w, int... indexes)
- {
- Float gw = new Float(w);
- for (int i = indexes.length - 1; i >= 0; i--) {
- int ix = indexes[i];
- makeSize(ix);
- cList.get(ix).setGrow(gw);
- }
- return this;
- }
-
- /** Specifies the current row/column's shrink priority.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @param p The new shrink priority.
- * @return <code>this</code> so it is possible to chain calls. E.g. <code>new AxisConstraint().noGrid().gap().fill()</code>.
- */
- public final AC shrinkPrio(int p)
- {
- return shrinkPrio(p, curIx);
- }
-
- /** Specifies the indicated rows'/columns' shrink priority.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @param p The new shrink priority.
- * @param indexes The index(es) (0-based) of the columns/rows that should be affected by this constraint.
- * @return <code>this</code> so it is possible to chain calls. E.g. <code>new AxisConstraint().noGrid().gap().fill()</code>.
- */
- public final AC shrinkPrio(int p, int... indexes)
- {
- for (int i = indexes.length - 1; i >= 0; i--) {
- int ix = indexes[i];
- makeSize(ix);
- cList.get(ix).setShrinkPriority(p);
- }
- return this;
- }
-
- /** Specifies that the current row/column's shrink weight withing the columns/rows with the same <code>shrink priority</code>.
- * <p>
- * For a more thorough explanation of what this constraint does see the White Paper or Cheat Sheet at www.migcomponents.com.
- * @param w The shrink weight.
- * @return <code>this</code> so it is possible to chain calls. E.g. <code>new AxisConstraint().noGrid().gap().fill()</code>.
- */
- public final AC shrinkWeight(float w)
- {
- return shrinkWeight(w, curIx);
- }
-
- /** Specifies the indicated rows'/columns' shrink weight withing the columns/rows with the same <code>shrink priority</code>.
- * <p>
- * For a more thorough explanation of what this constraint does see the White Paper or Cheat Sheet at www.migcomponents.com.
- * @param w The shrink weight.
- * @param indexes The index(es) (0-based) of the columns/rows that should be affected by this constraint.
- * @return <code>this</code> so it is possible to chain calls. E.g. <code>new AxisConstraint().noGrid().gap().fill()</code>.
- */
- public final AC shrinkWeight(float w, int... indexes)
- {
- Float sw = new Float(w);
- for (int i = indexes.length - 1; i >= 0; i--) {
- int ix = indexes[i];
- makeSize(ix);
- cList.get(ix).setShrink(sw);
- }
- return this;
- }
-
- private void makeSize(int sz)
- {
- if (cList.size() <= sz) {
- cList.ensureCapacity(sz);
- for (int i = cList.size(); i <= sz; i++)
- cList.add(new DimConstraint());
- }
- }
-
- // ************************************************
- // Persistence Delegate and Serializable combined.
- // ************************************************
-
- private Object readResolve() throws ObjectStreamException
- {
- return LayoutUtil.getSerializedObject(this);
- }
-
- public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException
- {
- LayoutUtil.setSerializedObject(this, LayoutUtil.readAsXML(in));
- }
-
- public void writeExternal(ObjectOutput out) throws IOException
- {
- if (getClass() == AC.class)
- LayoutUtil.writeAsXML(out, this);
- }
+package net.miginfocom.layout; + +import java.io.*; +import java.util.ArrayList; + +/* + * License (BSD): + * ============== + * + * Copyright (c) 2004, Mikael Grev, MiG InfoCom AB. (miglayout (at) miginfocom (dot) com) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright notice, this list + * of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * Neither the name of the MiG InfoCom AB nor the names of its contributors may be + * used to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * @version 1.0 + * @author Mikael Grev, MiG InfoCom AB + * Date: 2006-sep-08 + */ + +/** A constraint that holds the column <b>or</b> row constraints for the grid. It also holds the gaps between the rows and columns. + * <p> + * This class is a holder and builder for a number of {@link net.miginfocom.layout.DimConstraint}s. + * <p> + * For a more thorough explanation of what these constraints do, and how to build the constriants, see the White Paper or Cheat Sheet at www.migcomponents.com. + * <p> + * Note that there are two way to build this constraint. Through String (e.g. <code>"[100]3[200,fill]"</code> or through API (E.g. + * <code>new AxisConstraint().size("100").gap("3").size("200").fill()</code>. + */ +public final class AC implements Externalizable +{ + private final ArrayList<DimConstraint> cList = new ArrayList<DimConstraint>(8); + + private transient int curIx = 0; + + /** Constructor. Creates an instance that can be configured manually. Will be initialized with a default + * {@link net.miginfocom.layout.DimConstraint}. + */ + public AC() + { + cList.add(new DimConstraint()); + } + + /** Property. The different {@link net.miginfocom.layout.DimConstraint}s that this object consists of. + * These <code><DimConstraints/code> contains all information in this class. + * @return The different {@link net.miginfocom.layout.DimConstraint}s that this object consists of. A new list and + * never <code>null</code>. + */ + public final DimConstraint[] getConstaints() + { + return cList.toArray(new DimConstraint[cList.size()]); + } + + /** Sets the different {@link net.miginfocom.layout.DimConstraint}s that this object should consists of. + * @param constr The different {@link net.miginfocom.layout.DimConstraint}s that this object consists of. The list + * will be copied for storage. <code>null</code> or and emty array will reset the constaints to one <code>DimConstraint</code> + * with default values. + */ + public final void setConstaints(DimConstraint[] constr) + { + if (constr == null || constr.length < 1 ) + constr = new DimConstraint[] {new DimConstraint()}; + + cList.clear(); + cList.ensureCapacity(constr.length); + for (int i = 0; i < constr.length; i++) + cList.add(constr[i]); + } + + /** Returns the number of rows/columns that this constraints currently have. + * @return The number of rows/columns that this constraints currently have. At least 1. + */ + public int getCount() + { + return cList.size(); + } + + /** Sets the total number of rows/columns to <code>size</code>. If the number of rows/columns is already more + * than <code>size</code> nothing will happen. + * @param size The total number of rows/columns + * @return <code>this</code> so it is possible to chain calls. E.g. <code>new AxisConstraint().noGrid().gap().fill()</code>. + */ + public final AC count(int size) + { + makeSize(size); + return this; + } + + /** Specifies that the current row/column should not be grid-like. The while row/colum will have its components layed out + * in one single cell. It is the same as to say that the cells in this column/row will all be merged (a.k.a spanned). + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @return <code>this</code> so it is possible to chain calls. E.g. <code>new AxisConstraint().noGrid().gap().fill()</code>. + */ + public final AC noGrid() + { + return noGrid(curIx); + } + + /** Specifies that the indicated rows/columns should not be grid-like. The while row/colum will have its components layed out + * in one single cell. It is the same as to say that the cells in this column/row will all be merged (a.k.a spanned). + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @param indexes The index(es) (0-based) of the columns/rows that should be affected by this constraint. + * @return <code>this</code> so it is possible to chain calls. E.g. <code>new AxisConstraint().noGrid().gap().fill()</code>. + */ + public final AC noGrid(int... indexes) + { + for (int i = indexes.length - 1; i >= 0; i--) { + int ix = indexes[i]; + makeSize(ix); + cList.get(ix).setNoGrid(true); + } + return this; + } + + /** Sets the current row/column to <code>i</code>. If the current number of rows/columns is less than <code>i</code> a call + * to {@link #count(int)} will set the size accoringly. + * <p> + * The next call to any of the constriant methods (e.g. {@link net.miginfocom.layout.AC#noGrid}) will be carried + * out on this new row/column. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @param i The new current row/column. + * @return <code>this</code> so it is possible to chain calls. E.g. <code>new AxisConstraint().noGrid().gap().fill()</code>. + */ + public final AC index(int i) + { + makeSize(i); + curIx = i; + return this; + } + + /** Specifies that the current row/column's component should grow by default. It does not affect the size of the row/column. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @return <code>this</code> so it is possible to chain calls. E.g. <code>new AxisConstraint().noGrid().gap().fill()</code>. + */ + public final AC fill() + { + return fill(curIx); + } + + /** Specifies that the indicated rows'/columns' component should grow by default. It does not affect the size of the row/column. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @param indexes The index(es) (0-based) of the columns/rows that should be affected by this constraint. + * @return <code>this</code> so it is possible to chain calls. E.g. <code>new AxisConstraint().noGrid().gap().fill()</code>. + */ + public final AC fill(int... indexes) + { + for (int i = indexes.length - 1; i >= 0; i--) { + int ix = indexes[i]; + makeSize(ix); + cList.get(ix).setFill(true); + } + return this; + } + +// /** Specifies that the current row/column should be put in the end group <code>s</code> and will thus share the same ending +// * coordinate within the group. +// * <p> +// * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. +// * @param s A name to associate on the group that should be the same for other rows/columns in the same group. +// * @return <code>this</code> so it is possible to chain calls. E.g. <code>new AxisConstraint().noGrid().gap().fill()</code>. +// */ +// public final AxisConstraint endGroup(String s) +// { +// return endGroup(s, curIx); +// } +// +// /** Specifies that the indicated rows/columns should be put in the end group <code>s</code> and will thus share the same ending +// * coordinate within the group. +// * <p> +// * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. +// * @param s A name to associate on the group that should be the same for other rows/columns in the same group. +// * @param indexes The index(es) (0-based) of the columns/rows that should be affected by this constraint. +// * @return <code>this</code> so it is possible to chain calls. E.g. <code>new AxisConstraint().noGrid().gap().fill()</code>. +// */ +// public final AxisConstraint endGroup(String s, int... indexes) +// { +// for (int i = indexes.length - 1; i >= 0; i--) { +// int ix = indexes[i]; +// makeSize(ix); +// cList.get(ix).setEndGroup(s); +// } +// return this; +// } + + /** Specifies that the current row/column should be put in the size group <code>s</code> and will thus share the same size + * constraints as the other components in the group. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @param s A name to associate on the group that should be the same for other rows/columns in the same group. + * @return <code>this</code> so it is possible to chain calls. E.g. <code>new AxisConstraint().noGrid().gap().fill()</code>. + */ + public final AC sizeGroup(String s) + { + return sizeGroup(s, curIx); + } + + /** Specifies that the indicated rows/columns should be put in the size group <code>s</code> and will thus share the same size + * constraints as the other components in the group. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @param s A name to associate on the group that should be the same for other rows/columns in the same group. + * @param indexes The index(es) (0-based) of the columns/rows that should be affected by this constraint. + * @return <code>this</code> so it is possible to chain calls. E.g. <code>new AxisConstraint().noGrid().gap().fill()</code>. + */ + public final AC sizeGroup(String s, int... indexes) + { + for (int i = indexes.length - 1; i >= 0; i--) { + int ix = indexes[i]; + makeSize(ix); + cList.get(ix).setSizeGroup(s); + } + return this; + } + + /** Specifies the current row/column's min and/or preferred and/or max size. E.g. <code>"10px"</code> or <code>"50:100:200"</code>. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @param s The minimum and/or preferred and/or maximum size of this row. The string will be interpreted + * as a <b>BoundSize</b>. For more info on how <b>BoundSize</b> is formatted see the documentation. + * @return <code>this</code> so it is possible to chain calls. E.g. <code>new AxisConstraint().noGrid().gap().fill()</code>. + */ + public final AC size(String s) + { + return size(s, curIx); + } + + /** Specifies the indicated rows'/columns' min and/or preferred and/or max size. E.g. <code>"10px"</code> or <code>"50:100:200"</code>. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @param size The minimum and/or preferred and/or maximum size of this row. The string will be interpreted + * as a <b>BoundSize</b>. For more info on how <b>BoundSize</b> is formatted see the documentation. + * @param indexes The index(es) (0-based) of the columns/rows that should be affected by this constraint. + * @return <code>this</code> so it is possible to chain calls. E.g. <code>new AxisConstraint().noGrid().gap().fill()</code>. + */ + public final AC size(String size, int... indexes) + { + BoundSize bs = ConstraintParser.parseBoundSize(size, false, true); + for (int i = indexes.length - 1; i >= 0; i--) { + int ix = indexes[i]; + makeSize(ix); + cList.get(ix).setSize(bs); + } + return this; + } + + /** Specifies the gap size to be the default one <b>AND</b> moves to the next column/row. The method is called <code>.gap()</code> + * rather the more natural <code>.next()</code> to indicate that it is very much related to the other <code>.gap(..)</code> methods. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @return <code>this</code> so it is possible to chain calls. E.g. <code>new AxisConstraint().noGrid().gap().fill()</code>. + */ + public final AC gap() + { + curIx++; + return this; + } + + /** Specifies the gap size to <code>size</code> <b>AND</b> moves to the next column/row. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @param size minimum and/or preferred and/or maximum size of the gap between this and the next row/column. + * The string will be interpreted as a <b>BoundSize</b>. For more info on how <b>BoundSize</b> is formatted see the documentation. + * @return <code>this</code> so it is possible to chain calls. E.g. <code>new AxisConstraint().noGrid().gap().fill()</code>. + */ + public final AC gap(String size) + { + return gap(size, curIx++); + } + + /** Specifies the indicated rows'/columns' gap size to <code>size</code>. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @param size minimum and/or preferred and/or maximum size of the gap between this and the next row/column. + * The string will be interpreted as a <b>BoundSize</b>. For more info on how <b>BoundSize</b> is formatted see the documentation. + * @param indexes The index(es) (0-based) of the columns/rows that should be affected by this constraint. + * @return <code>this</code> so it is possible to chain calls. E.g. <code>new AxisConstraint().noGrid().gap().fill()</code>. + */ + public final AC gap(String size, int... indexes) + { + BoundSize bsa = size != null ? ConstraintParser.parseBoundSize(size, true, true) : null; + + for (int i = indexes.length - 1; i >= 0; i--) { + int ix = indexes[i]; + makeSize(ix); + if (bsa != null) + cList.get(ix).setGapAfter(bsa); + } + return this; + } + + /** Specifies the current row/column's columns default alignment <b>for its components</b>. It does not affect the positioning + * or size of the columns/row itself. For columns it is the horizonal alignment (e.g. "left") and for rows it is the vertical + * alignment (e.g. "top"). + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @param side The default side to align the components. E.g. "top" or "left", or "leading" or "trailing" or "bottom" or "right". + * @return <code>this</code> so it is possible to chain calls. E.g. <code>new AxisConstraint().noGrid().gap().fill()</code>. + */ + public final AC align(String side) + { + return align(side, curIx); + } + + /** Specifies the indicated rows'/columns' columns default alignment <b>for its components</b>. It does not affect the positioning + * or size of the columns/row itself. For columns it is the horizonal alignment (e.g. "left") and for rows it is the vertical + * alignment (e.g. "top"). + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @param side The default side to align the components. E.g. "top" or "left", or "before" or "after" or "bottom" or "right". + * @param indexes The index(es) (0-based) of the columns/rows that should be affected by this constraint. + * @return <code>this</code> so it is possible to chain calls. E.g. <code>new AxisConstraint().noGrid().gap().fill()</code>. + */ + public final AC align(String side, int... indexes) + { + UnitValue al = ConstraintParser.parseAlignKeywords(side, true); + if (al == null) + al = ConstraintParser.parseAlignKeywords(side, false); + + for (int i = indexes.length - 1; i >= 0; i--) { + int ix = indexes[i]; + makeSize(ix); + cList.get(ix).setAlign(al); + } + return this; + } + + /** Specifies the current row/column's grow priority. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @param p The new grow priority. + * @return <code>this</code> so it is possible to chain calls. E.g. <code>new AxisConstraint().noGrid().gap().fill()</code>. + */ + public final AC growPrio(int p) + { + return growPrio(p, curIx); + } + + /** Specifies the indicated rows'/columns' grow priority. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @param p The new grow priority. + * @param indexes The index(es) (0-based) of the columns/rows that should be affected by this constraint. + * @return <code>this</code> so it is possible to chain calls. E.g. <code>new AxisConstraint().noGrid().gap().fill()</code>. + */ + public final AC growPrio(int p, int... indexes) + { + for (int i = indexes.length - 1; i >= 0; i--) { + int ix = indexes[i]; + makeSize(ix); + cList.get(ix).setGrowPriority(p); + } + return this; + } + + /** Specifies the current row/column's grow weight within columns/rows with the same <code>grow priority</code>. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @param w The new grow weight. + * @return <code>this</code> so it is possible to chain calls. E.g. <code>new AxisConstraint().noGrid().gap().fill()</code>. + */ + public final AC grow(float w) + { + return grow(w, curIx); + } + + /** Specifies the indicated rows'/columns' grow weight within columns/rows with the same <code>grow priority</code>. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @param w The new grow weight. + * @param indexes The index(es) (0-based) of the columns/rows that should be affected by this constraint. + * @return <code>this</code> so it is possible to chain calls. E.g. <code>new AxisConstraint().noGrid().gap().fill()</code>. + */ + public final AC grow(float w, int... indexes) + { + Float gw = new Float(w); + for (int i = indexes.length - 1; i >= 0; i--) { + int ix = indexes[i]; + makeSize(ix); + cList.get(ix).setGrow(gw); + } + return this; + } + + /** Specifies the current row/column's shrink priority. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @param p The new shrink priority. + * @return <code>this</code> so it is possible to chain calls. E.g. <code>new AxisConstraint().noGrid().gap().fill()</code>. + */ + public final AC shrinkPrio(int p) + { + return shrinkPrio(p, curIx); + } + + /** Specifies the indicated rows'/columns' shrink priority. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @param p The new shrink priority. + * @param indexes The index(es) (0-based) of the columns/rows that should be affected by this constraint. + * @return <code>this</code> so it is possible to chain calls. E.g. <code>new AxisConstraint().noGrid().gap().fill()</code>. + */ + public final AC shrinkPrio(int p, int... indexes) + { + for (int i = indexes.length - 1; i >= 0; i--) { + int ix = indexes[i]; + makeSize(ix); + cList.get(ix).setShrinkPriority(p); + } + return this; + } + + /** Specifies that the current row/column's shrink weight withing the columns/rows with the same <code>shrink priority</code>. + * <p> + * For a more thorough explanation of what this constraint does see the White Paper or Cheat Sheet at www.migcomponents.com. + * @param w The shrink weight. + * @return <code>this</code> so it is possible to chain calls. E.g. <code>new AxisConstraint().noGrid().gap().fill()</code>. + */ + public final AC shrinkWeight(float w) + { + return shrinkWeight(w, curIx); + } + + /** Specifies the indicated rows'/columns' shrink weight withing the columns/rows with the same <code>shrink priority</code>. + * <p> + * For a more thorough explanation of what this constraint does see the White Paper or Cheat Sheet at www.migcomponents.com. + * @param w The shrink weight. + * @param indexes The index(es) (0-based) of the columns/rows that should be affected by this constraint. + * @return <code>this</code> so it is possible to chain calls. E.g. <code>new AxisConstraint().noGrid().gap().fill()</code>. + */ + public final AC shrinkWeight(float w, int... indexes) + { + Float sw = new Float(w); + for (int i = indexes.length - 1; i >= 0; i--) { + int ix = indexes[i]; + makeSize(ix); + cList.get(ix).setShrink(sw); + } + return this; + } + + private void makeSize(int sz) + { + if (cList.size() <= sz) { + cList.ensureCapacity(sz); + for (int i = cList.size(); i <= sz; i++) + cList.add(new DimConstraint()); + } + } + + // ************************************************ + // Persistence Delegate and Serializable combined. + // ************************************************ + + private Object readResolve() throws ObjectStreamException + { + return LayoutUtil.getSerializedObject(this); + } + + public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException + { + LayoutUtil.setSerializedObject(this, LayoutUtil.readAsXML(in)); + } + + public void writeExternal(ObjectOutput out) throws IOException + { + if (getClass() == AC.class) + LayoutUtil.writeAsXML(out, this); + } }
\ No newline at end of file diff --git a/prototypes/miglayout/net/miginfocom/layout/BoundSize.java b/prototypes/miglayout/net/miginfocom/layout/BoundSize.java index a5eeb32f..6da6eb40 100644 --- a/prototypes/miglayout/net/miginfocom/layout/BoundSize.java +++ b/prototypes/miglayout/net/miginfocom/layout/BoundSize.java @@ -1,246 +1,246 @@ -package net.miginfocom.layout;
-
-import java.beans.Encoder;
-import java.beans.Expression;
-import java.beans.PersistenceDelegate;
-import java.io.*;
-/*
- * License (BSD):
- * ==============
- *
- * Copyright (c) 2004, Mikael Grev, MiG InfoCom AB. (miglayout (at) miginfocom (dot) com)
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification,
- * are permitted provided that the following conditions are met:
- * Redistributions of source code must retain the above copyright notice, this list
- * of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above copyright notice, this
- * list of conditions and the following disclaimer in the documentation and/or other
- * materials provided with the distribution.
- * Neither the name of the MiG InfoCom AB nor the names of its contributors may be
- * used to endorse or promote products derived from this software without specific
- * prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
- * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
- * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
- * OF SUCH DAMAGE.
- *
- * @version 1.0
- * @author Mikael Grev, MiG InfoCom AB
- * Date: 2006-sep-08
- */
-
-/** A size that contains minimum, preferred and maximum size of type {@link UnitValue}.
- * <p>
- * This class is a simple value container and it is immutable.
- * <p>
- * If a size is missing (i.e., <code>null</code>) that boundary should be considered "not in use".
- * <p>
- * You can create a BoundSize from a String with the use of {@link ConstraintParser#parseBoundSize(String, boolean, boolean)}
- */
-public class BoundSize implements Serializable
-{
- public static final BoundSize ZERO_PIXEL = new BoundSize(UnitValue.ZERO, "0px");
-
- private final transient UnitValue min;
- private final transient UnitValue pref;
- private final transient UnitValue max;
- private final transient boolean gapPush;
-
- /** Constructor that use the same value for min/preferred/max size.
- * @param minMaxPref The value to use for min/preferred/max size.
- * @param createString The string used to create the BoundsSize.
- */
- public BoundSize(UnitValue minMaxPref, String createString)
- {
- this(minMaxPref, minMaxPref, minMaxPref, createString);
- }
-
- /** Constructor. <b>This method is here for serilization only and should normally not be used. Use
- * {@link ConstraintParser#parseBoundSize(String, boolean, boolean)} instead.
- * @param min The minimum size. May be <code>null</code>.
- * @param preferred The preferred size. May be <code>null</code>.
- * @param max The maximum size. May be <code>null</code>.
- * @param createString The string used to create the BoundsSize.
- */
- public BoundSize(UnitValue min, UnitValue preferred, UnitValue max, String createString) // Bound to old delegate!!!!!
- {
- this(min, preferred, max, false, createString);
- }
-
- /** Constructor. <b>This method is here for serilization only and should normally not be used. Use
- * {@link ConstraintParser#parseBoundSize(String, boolean, boolean)} instead.
- * @param min The minimum size. May be <code>null</code>.
- * @param preferred The preferred size. May be <code>null</code>.
- * @param max The maximum size. May be <code>null</code>.
- * @param gapPush If the size should be hinted as "pushing" and thus want to occupy free space if noone else is claiming it.
- * @param createString The string used to create the BoundsSize.
- */
- public BoundSize(UnitValue min, UnitValue preferred, UnitValue max, boolean gapPush, String createString)
- {
- this.min = min;
- this.pref = preferred;
- this.max = max;
- this.gapPush = gapPush;
-
- LayoutUtil.putCCString(this, createString); // this escapes!!
- }
-
- /** Returns the minimum size as sent into the constructor.
- * @return The minimum size as sent into the constructor. May be <code>null</code>.
- */
- public final UnitValue getMin()
- {
- return min;
- }
-
- /** Returns the preferred size as sent into the constructor.
- * @return The preferred size as sent into the constructor. May be <code>null</code>.
- */
- public final UnitValue getPreferred()
- {
- return pref;
- }
-
- /** Returns the maximum size as sent into the constructor.
- * @return The maximum size as sent into the constructor. May be <code>null</code>.
- */
- public final UnitValue getMax()
- {
- return max;
- }
-
- /** If the size should be hinted as "pushing" and thus want to occupy free space if noone else is claiming it.
- * @return The value.
- */
- public boolean getGapPush()
- {
- return gapPush;
- }
-
- /** Returns if this bound size has no min, preferred and maximum size set (they are all <code>null</code>)
- * @return If unset.
- */
- public boolean isUnset()
- {
- return pref == null && min == null && max == null;
- }
-
- /** Returns the minimum, preferred or maximum size for this bounded size.
- * @param sizeType The type. <code>LayoutUtil.MIN</code>, <code>LayoutUtil.PREF</code> or <code>LayoutUtil.MAX</code>.
- * @return
- */
- final UnitValue getSize(int sizeType)
- {
- switch(sizeType) {
- case LayoutUtil.MIN:
- return min;
- case LayoutUtil.PREF:
- return pref;
- case LayoutUtil.MAX:
- return max;
- default:
- throw new IllegalArgumentException("Unknown size: " + sizeType);
- }
- }
-
- /** Convert the bound sizes to pixels.
- * <p>
- * <code>null</code> bound sizes will be 0 for min and preferred and {@link net.miginfocom.layout.LayoutUtil#INF} for max.
- * @param refSize The reference size.
- * @param parent The parent. Not <code>null</code>.
- * @param comp The component, if applicable, can be <code>null</code>.
- * @return An array of lenth three (min,pref,max).
- */
- final int[] getPixelSizes(float refSize, ContainerWrapper parent, ComponentWrapper comp)
- {
- return new int[] {
- min != null ? min.getPixels(refSize, parent, comp) : 0,
- pref != null ? pref.getPixels(refSize, parent, comp) : 0,
- max != null ? max.getPixels(refSize, parent, comp) : LayoutUtil.INF
- };
- }
-
- /** Returns the a constraint string that can be re-parsed to be the exact same UnitValue.
- * @return A String. Never <code>null</code>.
- */
- String getConstraintString()
- {
- String cs = LayoutUtil.getCCString(this);
- if (cs != null)
- return cs;
-
- if (min == pref && pref == max)
- return min != null ? (min.getConstraintString() + "!") : "null";
-
- StringBuilder sb = new StringBuilder(16);
-
- if (min != null)
- sb.append(min.getConstraintString()).append(':');
-
- if (pref != null) {
- sb.append(pref.getConstraintString());
- } else if (min != null) {
- sb.append('n');
- }
-
- if (max != null)
- sb.append(sb.length() == 0 ? "::" : ":").append(max.getConstraintString());
-
- if (gapPush) {
- if (sb.length() > 0)
- sb.append(':');
- sb.append("push");
- }
-
- return sb.toString();
- }
-
- static {
- LayoutUtil.setDelegate(BoundSize.class, new PersistenceDelegate() {
- protected Expression instantiate(Object oldInstance, Encoder out)
- {
- BoundSize bs = (BoundSize) oldInstance;
- if (Grid.TEST_GAPS) {
- return new Expression(oldInstance, BoundSize.class, "new", new Object[] {
- bs.getMin(), bs.getPreferred(), bs.getMax(), bs.getGapPush(), bs.getConstraintString()
- });
- } else {
- return new Expression(oldInstance, BoundSize.class, "new", new Object[] {
- bs.getMin(), bs.getPreferred(), bs.getMax(), bs.getConstraintString()
- });
- }
- }
- });
- }
-
- // ************************************************
- // Persistence Delegate and Serializable combined.
- // ************************************************
-
- private static final long serialVersionUID = 1L;
-
- protected Object readResolve() throws ObjectStreamException
- {
- return LayoutUtil.getSerializedObject(this);
- }
-
- private void writeObject(ObjectOutputStream out) throws IOException
- {
- if (getClass() == BoundSize.class)
- LayoutUtil.writeAsXML(out, this);
- }
-
- private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException
- {
- LayoutUtil.setSerializedObject(this, LayoutUtil.readAsXML(in));
- }
+package net.miginfocom.layout; + +import java.beans.Encoder; +import java.beans.Expression; +import java.beans.PersistenceDelegate; +import java.io.*; +/* + * License (BSD): + * ============== + * + * Copyright (c) 2004, Mikael Grev, MiG InfoCom AB. (miglayout (at) miginfocom (dot) com) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright notice, this list + * of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * Neither the name of the MiG InfoCom AB nor the names of its contributors may be + * used to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * @version 1.0 + * @author Mikael Grev, MiG InfoCom AB + * Date: 2006-sep-08 + */ + +/** A size that contains minimum, preferred and maximum size of type {@link UnitValue}. + * <p> + * This class is a simple value container and it is immutable. + * <p> + * If a size is missing (i.e., <code>null</code>) that boundary should be considered "not in use". + * <p> + * You can create a BoundSize from a String with the use of {@link ConstraintParser#parseBoundSize(String, boolean, boolean)} + */ +public class BoundSize implements Serializable +{ + public static final BoundSize ZERO_PIXEL = new BoundSize(UnitValue.ZERO, "0px"); + + private final transient UnitValue min; + private final transient UnitValue pref; + private final transient UnitValue max; + private final transient boolean gapPush; + + /** Constructor that use the same value for min/preferred/max size. + * @param minMaxPref The value to use for min/preferred/max size. + * @param createString The string used to create the BoundsSize. + */ + public BoundSize(UnitValue minMaxPref, String createString) + { + this(minMaxPref, minMaxPref, minMaxPref, createString); + } + + /** Constructor. <b>This method is here for serilization only and should normally not be used. Use + * {@link ConstraintParser#parseBoundSize(String, boolean, boolean)} instead. + * @param min The minimum size. May be <code>null</code>. + * @param preferred The preferred size. May be <code>null</code>. + * @param max The maximum size. May be <code>null</code>. + * @param createString The string used to create the BoundsSize. + */ + public BoundSize(UnitValue min, UnitValue preferred, UnitValue max, String createString) // Bound to old delegate!!!!! + { + this(min, preferred, max, false, createString); + } + + /** Constructor. <b>This method is here for serilization only and should normally not be used. Use + * {@link ConstraintParser#parseBoundSize(String, boolean, boolean)} instead. + * @param min The minimum size. May be <code>null</code>. + * @param preferred The preferred size. May be <code>null</code>. + * @param max The maximum size. May be <code>null</code>. + * @param gapPush If the size should be hinted as "pushing" and thus want to occupy free space if noone else is claiming it. + * @param createString The string used to create the BoundsSize. + */ + public BoundSize(UnitValue min, UnitValue preferred, UnitValue max, boolean gapPush, String createString) + { + this.min = min; + this.pref = preferred; + this.max = max; + this.gapPush = gapPush; + + LayoutUtil.putCCString(this, createString); // this escapes!! + } + + /** Returns the minimum size as sent into the constructor. + * @return The minimum size as sent into the constructor. May be <code>null</code>. + */ + public final UnitValue getMin() + { + return min; + } + + /** Returns the preferred size as sent into the constructor. + * @return The preferred size as sent into the constructor. May be <code>null</code>. + */ + public final UnitValue getPreferred() + { + return pref; + } + + /** Returns the maximum size as sent into the constructor. + * @return The maximum size as sent into the constructor. May be <code>null</code>. + */ + public final UnitValue getMax() + { + return max; + } + + /** If the size should be hinted as "pushing" and thus want to occupy free space if noone else is claiming it. + * @return The value. + */ + public boolean getGapPush() + { + return gapPush; + } + + /** Returns if this bound size has no min, preferred and maximum size set (they are all <code>null</code>) + * @return If unset. + */ + public boolean isUnset() + { + return pref == null && min == null && max == null; + } + + /** Returns the minimum, preferred or maximum size for this bounded size. + * @param sizeType The type. <code>LayoutUtil.MIN</code>, <code>LayoutUtil.PREF</code> or <code>LayoutUtil.MAX</code>. + * @return + */ + final UnitValue getSize(int sizeType) + { + switch(sizeType) { + case LayoutUtil.MIN: + return min; + case LayoutUtil.PREF: + return pref; + case LayoutUtil.MAX: + return max; + default: + throw new IllegalArgumentException("Unknown size: " + sizeType); + } + } + + /** Convert the bound sizes to pixels. + * <p> + * <code>null</code> bound sizes will be 0 for min and preferred and {@link net.miginfocom.layout.LayoutUtil#INF} for max. + * @param refSize The reference size. + * @param parent The parent. Not <code>null</code>. + * @param comp The component, if applicable, can be <code>null</code>. + * @return An array of lenth three (min,pref,max). + */ + final int[] getPixelSizes(float refSize, ContainerWrapper parent, ComponentWrapper comp) + { + return new int[] { + min != null ? min.getPixels(refSize, parent, comp) : 0, + pref != null ? pref.getPixels(refSize, parent, comp) : 0, + max != null ? max.getPixels(refSize, parent, comp) : LayoutUtil.INF + }; + } + + /** Returns the a constraint string that can be re-parsed to be the exact same UnitValue. + * @return A String. Never <code>null</code>. + */ + String getConstraintString() + { + String cs = LayoutUtil.getCCString(this); + if (cs != null) + return cs; + + if (min == pref && pref == max) + return min != null ? (min.getConstraintString() + "!") : "null"; + + StringBuilder sb = new StringBuilder(16); + + if (min != null) + sb.append(min.getConstraintString()).append(':'); + + if (pref != null) { + sb.append(pref.getConstraintString()); + } else if (min != null) { + sb.append('n'); + } + + if (max != null) + sb.append(sb.length() == 0 ? "::" : ":").append(max.getConstraintString()); + + if (gapPush) { + if (sb.length() > 0) + sb.append(':'); + sb.append("push"); + } + + return sb.toString(); + } + + static { + LayoutUtil.setDelegate(BoundSize.class, new PersistenceDelegate() { + protected Expression instantiate(Object oldInstance, Encoder out) + { + BoundSize bs = (BoundSize) oldInstance; + if (Grid.TEST_GAPS) { + return new Expression(oldInstance, BoundSize.class, "new", new Object[] { + bs.getMin(), bs.getPreferred(), bs.getMax(), bs.getGapPush(), bs.getConstraintString() + }); + } else { + return new Expression(oldInstance, BoundSize.class, "new", new Object[] { + bs.getMin(), bs.getPreferred(), bs.getMax(), bs.getConstraintString() + }); + } + } + }); + } + + // ************************************************ + // Persistence Delegate and Serializable combined. + // ************************************************ + + private static final long serialVersionUID = 1L; + + protected Object readResolve() throws ObjectStreamException + { + return LayoutUtil.getSerializedObject(this); + } + + private void writeObject(ObjectOutputStream out) throws IOException + { + if (getClass() == BoundSize.class) + LayoutUtil.writeAsXML(out, this); + } + + private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException + { + LayoutUtil.setSerializedObject(this, LayoutUtil.readAsXML(in)); + } }
\ No newline at end of file diff --git a/prototypes/miglayout/net/miginfocom/layout/CC.java b/prototypes/miglayout/net/miginfocom/layout/CC.java index 1fe75e2c..304f36ce 100644 --- a/prototypes/miglayout/net/miginfocom/layout/CC.java +++ b/prototypes/miglayout/net/miginfocom/layout/CC.java @@ -1,1543 +1,1543 @@ -package net.miginfocom.layout;
-
-import java.io.*;
-/*
- * License (BSD):
- * ==============
- *
- * Copyright (c) 2004, Mikael Grev, MiG InfoCom AB. (miglayout (at) miginfocom (dot) com)
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification,
- * are permitted provided that the following conditions are met:
- * Redistributions of source code must retain the above copyright notice, this list
- * of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above copyright notice, this
- * list of conditions and the following disclaimer in the documentation and/or other
- * materials provided with the distribution.
- * Neither the name of the MiG InfoCom AB nor the names of its contributors may be
- * used to endorse or promote products derived from this software without specific
- * prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
- * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
- * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
- * OF SUCH DAMAGE.
- *
- * @version 1.0
- * @author Mikael Grev, MiG InfoCom AB
- * Date: 2006-sep-08
- */
-
-/** A simple value holder for one component's constraint.
- */
-public final class CC implements Externalizable
-{
- private static final BoundSize DEF_GAP = new BoundSize(null, null); // Only used to denote default wrap/newline gap.
-
- static final String[] DOCK_SIDES = {"north", "west", "south", "east"};
-
- // See the getters and setters for information about the properties below.
-
- private int dock = -1;
-
- private UnitValue[] pos = null; // [x1, y1, x2, y2]
-
- private UnitValue[] padding = null; // top, left, bottom, right
-
- private Boolean flowX = null;
-
- private int skip = 0;
-
- private int split = 1;
-
- private int spanX = 1, spanY = 1;
-
- private int cellX = -1, cellY = 0; // If cellX is -1 then cellY is also considered -1. cellY is never negative.
-
- private String tag = null;
-
- private String id = null;
-
- private int hideMode = -1;
-
- private DimConstraint hor = new DimConstraint();
-
- private DimConstraint ver = new DimConstraint();
-
- private BoundSize newline = null;
-
- private BoundSize wrap = null;
-
- private boolean boundsInGrid = true;
-
- private boolean external = false;
-
- private Float pushX = null, pushY = null;
-
-
- /** Empty constructor.
- */
- public CC()
- {
- }
-
- // **********************************************************
- // Chaining constraint setters
- // **********************************************************
-
- /** Specifies that the component should be put in the end group <code>s</code> and will thus share the same ending
- * coordinate as them within the group.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @param s A name to associate on the group that should be the same for other rows/columns in the same group.
- * @return <code>this</code> so it is possible to chain calls. E.g. <code>new ComponentConstraint().noGrid().gap().fill()</code>.
- */
- public final CC endGroupX(String s)
- {
- hor.setEndGroup(s);
- return this;
- }
-
- /** Specifies that the component should be put in the size group <code>s</code> and will thus share the same size
- * as them within the group.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @param s A name to associate on the group that should be the same for other rows/columns in the same group.
- * @return <code>this</code> so it is possible to chain calls. E.g. <code>new ComponentConstraint().noGrid().gap().fill()</code>.
- */
- public final CC sizeGroupX(String s)
- {
- hor.setSizeGroup(s);
- return this;
- }
-
- /** The minimum size for the component. The value will override any value that is set on the component itself.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @param size The size expressed as a <code>UnitValue</code>. E.g. "100px" or "200mm".
- * @return <code>this</code> so it is possible to chain calls. E.g. <code>new ComponentConstraint().noGrid().gap().fill()</code>.
- */
- public final CC minWidth(String size)
- {
- hor.setSize(LayoutUtil.derive(hor.getSize(), ConstraintParser.parseUnitValue(size, true), null, null));
- return this;
- }
-
- /** The size for the component as a min and/or preferref and/or maximum size. The value will override any value that is set on
- * the component itself.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @param size The size expressed as a <code>BoundSize</code>. E.g. "50:100px:200mm" or "100px".
- * @return <code>this</code> so it is possible to chain calls. E.g. <code>new ComponentConstraint().noGrid().gap().fill()</code>.
- */
- public final CC width(String size)
- {
- hor.setSize(ConstraintParser.parseBoundSize(size, false, true));
- return this;
- }
-
- /** The maximum size for the component. The value will override any value that is set on the component itself.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @param size The size expressed as a <code>UnitValue</code>. E.g. "100px" or "200mm".
- * @return <code>this</code> so it is possible to chain calls. E.g. <code>new ComponentConstraint().noGrid().gap().fill()</code>.
- */
- public final CC maxWidth(String size)
- {
- hor.setSize(LayoutUtil.derive(hor.getSize(), null, null, ConstraintParser.parseUnitValue(size, true)));
- return this;
- }
-
-
- /** The horizontal gap before and/or after the component. The gap is towards cell bounds and/or other component bounds.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @param before The size of the gap expressed as a <code>BoundSize</code>. E.g. "50:100px:200mm" or "100px!".
- * @param after The size of the gap expressed as a <code>BoundSize</code>. E.g. "50:100px:200mm" or "100px!".
- * @return <code>this</code> so it is possible to chain calls. E.g. <code>new ComponentConstraint().noGrid().gap().fill()</code>.
- */
- public final CC gapX(String before, String after)
- {
- if (before != null)
- hor.setGapBefore(ConstraintParser.parseBoundSize(before, true, true));
-
- if (after != null)
- hor.setGapAfter(ConstraintParser.parseBoundSize(after, true, true));
-
- return this;
- }
-
- /** Same functionality as <code>getHorizontal().setAlign(ConstraintParser.parseUnitValue(unitValue, true))</code> only this method
- * returns <code>this</code> for chaining multiple calls.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @param align The align keyword or for instance "100px". E.g "left", "right", "leading" or "trailing".
- * @return <code>this</code> so it is possible to chain calls. E.g. <code>new ComponentConstraint().noGrid().gap().fill()</code>.
- */
- public final CC alignX(String align)
- {
- hor.setAlign(ConstraintParser.parseUnitValueOrAlign(align, true, null));
- return this;
- }
-
- /** The grow priority compared to other components in the same cell.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @param p The grow priority.
- * @return <code>this</code> so it is possible to chain calls. E.g. <code>new ComponentConstraint().noGrid().gap().fill()</code>.
- */
- public final CC growPrioX(int p)
- {
- hor.setGrowPriority(p);
- return this;
- }
-
- /** Grow weight for the component horizontally. It default to weight <code>100</code>.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @return <code>this</code> so it is possible to chain calls. E.g. <code>new ComponentConstraint().noGrid().gap().fill()</code>.
- * @see #growX(float)
- */
- public final CC growX()
- {
- hor.setGrow(ResizeConstraint.WEIGHT_100);
- return this;
- }
-
- /** Grow weight for the component horizontally.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @param w The new grow weight.
- * @return <code>this</code> so it is possible to chain calls. E.g. <code>new ComponentConstraint().noGrid().gap().fill()</code>.
- */
- public final CC growX(float w)
- {
- hor.setGrow(new Float(w));
- return this;
- }
-
- /** The shrink priority compared to other components in the same cell.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @param p The shrink priority.
- * @return <code>this</code> so it is possible to chain calls. E.g. <code>new ComponentConstraint().noGrid().gap().fill()</code>.
- */
- public final CC shrinkPrioX(int p)
- {
- hor.setShrinkPriority(p);
- return this;
- }
-
- /** Shrink weight for the component horizontally.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @param w The new shrink weight.
- * @return <code>this</code> so it is possible to chain calls. E.g. <code>new ComponentConstraint().noGrid().gap().fill()</code>.
- */
- public final CC shrinkX(float w)
- {
- hor.setShrink(new Float(w));
- return this;
- }
-
- /** The end group that this componet should be placed in.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @param s The name of the group. If <code>null</code> that means no group (default)
- * @return <code>this</code> so it is possible to chain calls. E.g. <code>new ComponentConstraint().noGrid().gap().fill()</code>.
- */
- public final CC endGroupY(String s)
- {
- ver.setEndGroup(s);
- return this;
- }
-
- /** The size group that this componet should be placed in.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @param s The name of the group. If <code>null</code> that means no group (default)
- * @return <code>this</code> so it is possible to chain calls. E.g. <code>new ComponentConstraint().noGrid().gap().fill()</code>.
- */
- public final CC sizeGroupY(String s)
- {
- ver.setSizeGroup(s);
- return this;
- }
-
- /** The minimum size for the component. The value will override any value that is set on the component itself.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @param size The size expressed as a <code>UnitValue</code>. E.g. "100px" or "200mm".
- * @return <code>this</code> so it is possible to chain calls. E.g. <code>new ComponentConstraint().noGrid().gap().fill()</code>.
- */
- public final CC minHeight(String size)
- {
- ver.setSize(LayoutUtil.derive(ver.getSize(), ConstraintParser.parseUnitValue(size, false), null, null));
- return this;
- }
-
- /** The size for the component as a min and/or preferref and/or maximum size. The value will override any value that is set on
- * the component itself.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @param size The size expressed as a <code>BoundSize</code>. E.g. "50:100px:200mm" or "100px".
- * @return <code>this</code> so it is possible to chain calls. E.g. <code>new ComponentConstraint().noGrid().gap().fill()</code>.
- */
- public final CC height(String size)
- {
- ver.setSize(ConstraintParser.parseBoundSize(size, false, false));
- return this;
- }
-
- /** The maximum size for the component. The value will override any value that is set on the component itself.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @param size The size expressed as a <code>UnitValue</code>. E.g. "100px" or "200mm".
- * @return <code>this</code> so it is possible to chain calls. E.g. <code>new ComponentConstraint().noGrid().gap().fill()</code>.
- */
- public final CC maxHeight(String size)
- {
- ver.setSize(LayoutUtil.derive(ver.getSize(), null, null, ConstraintParser.parseUnitValue(size, false)));
- return this;
- }
-
- /** The vertical gap before (normally above) and/or after (normally below) the component. The gap is towards cell bounds and/or other component bounds.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @param before The size of the gap expressed as a <code>BoundSize</code>. E.g. "50:100px:200mm" or "100px!".
- * @param after The size of the gap expressed as a <code>BoundSize</code>. E.g. "50:100px:200mm" or "100px!".
- * @return <code>this</code> so it is possible to chain calls. E.g. <code>new ComponentConstraint().noGrid().gap().fill()</code>.
- */
- public final CC gapY(String before, String after)
- {
- if (before != null)
- ver.setGapBefore(ConstraintParser.parseBoundSize(before, true, false));
-
- if (after != null)
- ver.setGapAfter(ConstraintParser.parseBoundSize(after, true, false));
-
- return this;
- }
-
- /** Same functionality as <code>getVertical().setAlign(ConstraintParser.parseUnitValue(unitValue, true))</code> only this method
- * returns <code>this</code> for chaining multiple calls.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @param align The align keyword or for instance "100px". E.g "top" or "bottom".
- * @return <code>this</code> so it is possible to chain calls. E.g. <code>new ComponentConstraint().noGrid().gap().fill()</code>.
- */
- public final CC alignY(String align)
- {
- ver.setAlign(ConstraintParser.parseUnitValueOrAlign(align, false, null));
- return this;
- }
-
- /** The grow priority compared to other components in the same cell.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @param p The grow priority.
- * @return <code>this</code> so it is possible to chain calls. E.g. <code>new ComponentConstraint().noGrid().gap().fill()</code>.
- */
- public final CC growPrioY(int p)
- {
- ver.setGrowPriority(p);
- return this;
- }
-
- /** Grow weight for the component vertically. Defaults to <code>100</code>.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @return <code>this</code> so it is possible to chain calls. E.g. <code>new ComponentConstraint().noGrid().gap().fill()</code>.
- * @see #growY(Float)
- */
- public final CC growY()
- {
- ver.setGrow(ResizeConstraint.WEIGHT_100);
- return this;
- }
-
- /** Grow weight for the component vertically.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @param w The new grow weight.
- * @return <code>this</code> so it is possible to chain calls. E.g. <code>new ComponentConstraint().noGrid().gap().fill()</code>.
- */
- public final CC growY(Float w)
- {
- ver.setGrow(w);
- return this;
- }
-
- /** The shrink priority compared to other components in the same cell.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @param p The shrink priority.
- * @return <code>this</code> so it is possible to chain calls. E.g. <code>new ComponentConstraint().noGrid().gap().fill()</code>.
- */
- public final CC shrinkPrioY(int p)
- {
- ver.setShrinkPriority(p);
- return this;
- }
-
- /** Shrink weight for the component horizontally.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @param w The new shrink weight.
- * @return <code>this</code> so it is possible to chain calls. E.g. <code>new ComponentConstraint().noGrid().gap().fill()</code>.
- */
- public final CC shrinkY(float w)
- {
- ver.setShrink(new Float(w));
- return this;
- }
-
- /** How this component, if hidden (not visible), should be treated.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @param mode The mode. Default to the mode in the {@link net.miginfocom.layout.LC}.
- * 0 == Normal. Bounds will be calculated as if the component was visible.<br>
- * 1 == If hidden the size will be 0, 0 but the gaps remain.<br>
- * 2 == If hidden the size will be 0, 0 and gaps set to zero.<br>
- * 3 == If hidden the component will be disregarded completely and not take up a cell in the grid..
- * @return <code>this</code> so it is possible to chain calls. E.g. <code>new ComponentConstraint().noGrid().gap().fill()</code>.
- */
- public final CC hideMode(int mode)
- {
- setHideMode(mode);
- return this;
- }
-
- /** The id used to reference this component in some constraints.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @param s The id or <code>null</code>. May consist of a groupID and an componentID which are separated by a dot: ".". E.g. "grp1.id1".
- * The dot should never be first or last if present.
- * @return <code>this</code> so it is possible to chain calls. E.g. <code>new ComponentConstraint().noGrid().gap().fill()</code>.
- */
- public final CC id(String s)
- {
- setId(s);
- return this;
- }
-
- /** Same functionality as {@link #setTag(String tag)} only this method returns <code>this</code> for chaining multiple calls.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @param tag The new tag. May be <code>null</code>.
- * @return <code>this</code> so it is possible to chain calls. E.g. <code>new LayoutConstraint().noGrid().gap().fill()</code>.
- * @see #setTag(String)
- */
- public final CC tag(String tag)
- {
- setTag(tag);
- return this;
- }
-
- /** Same functionality as {@link #setCellX(int col)} and {@link #setCellY(int row)} only this method returns <code>this</code> for chaining multiple calls.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @param col The column in the grid to place this component.
- * @param row The rw in the grid to place this component.
- * @return <code>this</code> so it is possible to chain calls. E.g. <code>new LayoutConstraint().noGrid().gap().fill()</code>.
- * @see #setCellX(int)
- * @see #setCellY(int)
- */
- public final CC cell(int col, int row)
- {
- setCellX(col);
- setCellY(row);
- return this;
- }
-
- /** Set the cell(s) that the component should occupy in the grid. Same functionality as {@link #setCellX(int col)} and
- * {@link #setCellY(int row)} together with {@link #setSpanX(int width)} and {@link #setSpanY(int height)}. This method
- * returns <code>this</code> for chaining multiple calls.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @param col The column in the grid to place this component.
- * @param row The rw in the grid to place this component.
- * @param width How many cells the component should span (i.e. merge). <code>LayoutUtil.INF</code> spans to the end of the row.
- * @param height How many cells the component should span (i.e. merge). <code>LayoutUtil.INF</code> spans to the end of the column.
- * @return <code>this</code> so it is possible to chain calls. E.g. <code>new LayoutConstraint().noGrid().gap().fill()</code>.
- * @see #setCellX(int)
- * @see #setCellY(int)
- */
- public final CC cell(int col, int row, int width, int height)
- {
- setCellX(col);
- setCellY(row);
- setSpanX(width);
- setSpanY(height);
- return this;
- }
-
- /** Same functionality as <code>spanX(cellsX).spanY(cellsY)</code> which means this cell will span cells in both x and y.
- * This method returns <code>this</code> for chaining multiple calls.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @return <code>this</code> so it is possible to chain calls. E.g. <code>new LayoutConstraint().noGrid().gap().fill()</code>.
- * @see #setSpanY(int)
- * @see #setSpanX(int)
- * @see #spanY()
- * @see #spanX()
- */
- public final CC span(int cellsX, int cellsY)
- {
- return spanX(cellsX).spanY(cellsY);
- }
-
- /** Same functionality as {@link #setSpanY(int LayoutUtil.INF)} which means this cell will span the rest of the column.
- * This method returns <code>this</code> for chaining multiple calls.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @return <code>this</code> so it is possible to chain calls. E.g. <code>new LayoutConstraint().noGrid().gap().fill()</code>.
- * @see #setSpanY(int)
- * @see #spanY()
- */
- public final CC spanY()
- {
- return spanY(LayoutUtil.INF);
- }
-
- /** Same functionality as {@link #setSpanY(int cells)} only this method returns <code>this</code> for chaining multiple calls.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @param cells The number of cells to span (i.e. merge).
- * @return <code>this</code> so it is possible to chain calls. E.g. <code>new LayoutConstraint().noGrid().gap().fill()</code>.
- * @see #setSpanY(int)
- */
- public final CC spanY(int cells)
- {
- setSpanY(cells);
- return this;
- }
-
- /** Same functionality as {@link #setSpanX(int LayoutUtil.INF)} which means this cell will span the rest of the row.
- * This method returns <code>this</code> for chaining multiple calls.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @return <code>this</code> so it is possible to chain calls. E.g. <code>new LayoutConstraint().noGrid().gap().fill()</code>.
- * @see #setSpanX(int)
- * @see #spanX()
- */
- public final CC spanX()
- {
- return spanX(LayoutUtil.INF);
- }
-
- /** Same functionality as {@link #setSpanX(int cells)} only this method returns <code>this</code> for chaining multiple calls.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @param cells The number of cells to span (i.e. merge).
- * @return <code>this</code> so it is possible to chain calls. E.g. <code>new LayoutConstraint().noGrid().gap().fill()</code>.
- * @see #setSpanY(int)
- */
- public final CC spanX(int cells)
- {
- setSpanX(cells);
- return this;
- }
-
- /** Same functionality as <code>pushX().pushY()</code> which means this cell will push in both x and y dimensions.
- * This method returns <code>this</code> for chaining multiple calls.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @return <code>this</code> so it is possible to chain calls. E.g. <code>new LayoutConstraint().noGrid().gap().fill()</code>.
- * @see #setPushX(Float)
- * @see #setPushX(Float)
- * @see #pushY()
- * @see #pushX()
- */
- public final CC push()
- {
- return pushX().pushY();
- }
-
- /** Same functionality as <code>pushX(weightX).pushY(weightY)</code> which means this cell will push in both x and y dimensions.
- * This method returns <code>this</code> for chaining multiple calls.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @param weightX The weight used in the push.
- * @param weightY The weight used in the push.
- * @return <code>this</code> so it is possible to chain calls. E.g. <code>new LayoutConstraint().noGrid().gap().fill()</code>.
- * @see #setPushY(Float)
- * @see #setPushX(Float)
- * @see #pushY()
- * @see #pushX()
- */
- public final CC push(Float weightX, Float weightY)
- {
- return pushX(weightX).pushY(weightY);
- }
-
- /** Same functionality as {@link #setPushY(Float))} which means this cell will push the rest of the column.
- * This method returns <code>this</code> for chaining multiple calls.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @return <code>this</code> so it is possible to chain calls. E.g. <code>new LayoutConstraint().noGrid().gap().fill()</code>.
- * @see #setPushY(Float)
- * @see #pushY()
- */
- public final CC pushY()
- {
- return pushY(ResizeConstraint.WEIGHT_100);
- }
-
- /** Same functionality as {@link #setPushY(Float weight)} only this method returns <code>this</code> for chaining multiple calls.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @param weight The weight used in the push.
- * @return <code>this</code> so it is possible to chain calls. E.g. <code>new LayoutConstraint().noGrid().gap().fill()</code>.
- * @see #setPushY(Float)
- */
- public final CC pushY(Float weight)
- {
- setPushY(weight);
- return this;
- }
-
- /** Same functionality as {@link #setPushX(Float)} which means this cell will push the rest of the row.
- * This method returns <code>this</code> for chaining multiple calls.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @return <code>this</code> so it is possible to chain calls. E.g. <code>new LayoutConstraint().noGrid().gap().fill()</code>.
- * @see #setPushX(Float)
- * @see #pushX()
- */
- public final CC pushX()
- {
- return pushX(ResizeConstraint.WEIGHT_100);
- }
-
- /** Same functionality as {@link #setPushX(Float weight)} only this method returns <code>this</code> for chaining multiple calls.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @param weight The weight used in the push.
- * @return <code>this</code> so it is possible to chain calls. E.g. <code>new LayoutConstraint().noGrid().gap().fill()</code>.
- * @see #setPushY(Float)
- */
- public final CC pushX(Float weight)
- {
- setPushX(weight);
- return this;
- }
-
- /** Same functionality as {@link #setSplit(int parts)} only this method returns <code>this</code> for chaining multiple calls.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @param parts The number of parts (i.e. component slots) the cell should be divided into.
- * @return <code>this</code> so it is possible to chain calls. E.g. <code>new ComponentConstraint().noGrid().gap().fill()</code>.
- * @see #setSplit(int)
- */
- public final CC split(int parts)
- {
- setSplit(parts);
- return this;
- }
-
- /** Same functionality as {@link #setSkip(int)} only this method returns <code>this</code> for chaining multiple calls.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @param cells How many cells in the grid that should be skipped <b>before</b> the component that this constraint belongs to
- * @return <code>this</code> so it is possible to chain calls. E.g. <code>new ComponentConstraint().noGrid().gap().fill()</code>.
- * @see #setSkip(int)
- */
- public final CC skip(int cells)
- {
- setSkip(cells);
- return this;
- }
-
- /** Same functionality as {@link #setExternal(boolean true)} only this method returns <code>this</code> for chaining multiple calls.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @return <code>this</code> so it is possible to chain calls. E.g. <code>new ComponentConstraint().noGrid().gap().fill()</code>.
- * @see #setExternal(boolean)
- */
- public final CC external()
- {
- setExternal(true);
- return this;
- }
-
- /** Same functionality as {@link #setFlowX(Boolean .TRUE)} only this method returns <code>this</code> for chaining multiple calls.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @return <code>this</code> so it is possible to chain calls. E.g. <code>new ComponentConstraint().noGrid().gap().fill()</code>.
- * @see #setFlowX(Boolean)
- */
- public final CC flowX()
- {
- setFlowX(Boolean.TRUE);
- return this;
- }
-
- /** Same functionality as {@link #setFlowX(Boolean .FALSE)} only this method returns <code>this</code> for chaining multiple calls.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @return <code>this</code> so it is possible to chain calls. E.g. <code>new ComponentConstraint().noGrid().gap().fill()</code>.
- * @see #setFlowX(Boolean)
- */
- public final CC flowY()
- {
- setFlowX(Boolean.FALSE);
- return this;
- }
-
-
- /** Same functionality as {@link #growX()} and {@link #growY()}.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @return <code>this</code> so it is possible to chain calls. E.g. <code>new ComponentConstraint().noGrid().gap().fill()</code>.
- * @see #growX()
- * @see #growY()
- */
- public final CC grow()
- {
- growX();
- growY();
- return this;
- }
-
- /** Same functionality as {@link #setNewline(boolean true)} only this method returns <code>this</code> for chaining multiple calls.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @return <code>this</code> so it is possible to chain calls. E.g. <code>new ComponentConstraint().noGrid().gap().fill()</code>.
- * @see #setNewline(boolean)
- */
- public final CC newline()
- {
- setNewline(true);
- return this;
- }
-
- /** Same functionality as {@link #setNewlineGapSize(BoundString)} only this method returns <code>this</code> for chaining multiple calls.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @param gapSize The gap size that will override the gap size in the row/colum constraints if <code>!= null</code>. E.g. "5px" or "unrel".
- * If <code>null</code> or <code>""</code> the newline size will be set to the default size and turned on. This is different compared to
- * {@link #setNewlineGapSize(BoundString)}.
- * @return <code>this</code> so it is possible to chain calls. E.g. <code>new ComponentConstraint().noGrid().gap().fill()</code>.
- * @see #setNewlineGapSize(BoundSize)
- */
- public final CC newline(String gapSize)
- {
- BoundSize bs = ConstraintParser.parseBoundSize(gapSize, true, (flowX != null && flowX == false));
- if (bs != null) {
- setNewlineGapSize(bs);
- } else {
- setNewline(true);
- }
- return this;
- }
-
- /** Same functionality as {@link #setWrap(boolean true)} only this method returns <code>this</code> for chaining multiple calls.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @return <code>this</code> so it is possible to chain calls. E.g. <code>new ComponentConstraint().noGrid().gap().fill()</code>.
- * @see #setWrap(boolean)
- */
- public final CC wrap()
- {
- setWrap(true);
- return this;
- }
-
- /** Same functionality as {@link #setWrapGapSize(BoundString)} only this method returns <code>this</code> for chaining multiple calls.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @param gapSize The gap size that will override the gap size in the row/colum constraints if <code>!= null</code>. E.g. "5px" or "unrel".
- * If <code>null</code> or <code>""</code> the wrap size will be set to the default size and turned on. This is different compared to
- * {@link #setWrapGapSize(BoundString)}.
- * @return <code>this</code> so it is possible to chain calls. E.g. <code>new ComponentConstraint().noGrid().gap().fill()</code>.
- * @see #setWrapGapSize(BoundSize)
- */
- public final CC wrap(String gapSize)
- {
- BoundSize bs = ConstraintParser.parseBoundSize(gapSize, true, (flowX != null && flowX == false));
- if (bs != null) {
- setWrapGapSize(bs);
- } else {
- setWrap(true);
- }
- return this;
- }
-
- /** Same functionality as {@link #setDockSide(int 0)} only this method returns <code>this</code> for chaining multiple calls.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @return <code>this</code> so it is possible to chain calls. E.g. <code>new ComponentConstraint().noGrid().gap().fill()</code>.
- * @see #setDockSide(int)
- */
- public final CC dockNorth()
- {
- setDockSide(0);
- return this;
- }
-
- /** Same functionality as {@link #setDockSide(int 1)} only this method returns <code>this</code> for chaining multiple calls.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @return <code>this</code> so it is possible to chain calls. E.g. <code>new ComponentConstraint().noGrid().gap().fill()</code>.
- * @see #setDockSide(int)
- */
- public final CC dockWest()
- {
- setDockSide(1);
- return this;
- }
-
- /** Same functionality as {@link #setDockSide(int 2)} only this method returns <code>this</code> for chaining multiple calls.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @return <code>this</code> so it is possible to chain calls. E.g. <code>new ComponentConstraint().noGrid().gap().fill()</code>.
- * @see #setDockSide(int)
- */
- public final CC dockSouth()
- {
- setDockSide(2);
- return this;
- }
-
- /** Same functionality as {@link #setDockSide(int 3)} only this method returns <code>this</code> for chaining multiple calls.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @return <code>this</code> so it is possible to chain calls. E.g. <code>new ComponentConstraint().noGrid().gap().fill()</code>.
- * @see #setDockSide(int)
- */
- public final CC dockEast()
- {
- setDockSide(3);
- return this;
- }
-
- /** Sets the x-coordinate for the component. This is used to set the x coordinate position to a specific value. The component
- * bounds is still precalculated to the grid cell and this method should be seen as a way to correct the x position.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @param x The x position as a UnitValue. E.g. "10" or "40mm" or "container.x+10".
- * @return <code>this</code> so it is possible to chain calls. E.g. <code>new ComponentConstraint().noGrid().gap().fill()</code>.
- * @see #setPos(UnitValue[])
- * @see #setBoundsInGrid(boolean)
- */
- public final CC x(String x)
- {
- return corrPos(x, 0);
- }
-
- /** Sets the y-coordinate for the component. This is used to set the y coordinate position to a specific value. The component
- * bounds is still precalculated to the grid cell and this method should be seen as a way to correct the y position.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @param y The y position as a UnitValue. E.g. "10" or "40mm" or "container.x+10".
- * @return <code>this</code> so it is possible to chain calls. E.g. <code>new ComponentConstraint().noGrid().gap().fill()</code>.
- * @see #setPos(UnitValue[])
- * @see #setBoundsInGrid(boolean)
- */
- public final CC y(String y)
- {
- return corrPos(y, 1);
- }
-
- /** Sets the x2-coordinate for the component (right side). This is used to set the x2 coordinate position to a specific value. The component
- * bounds is still precalculated to the grid cell and this method should be seen as a way to correct the x position.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @param x2 The x2 side's position as a UnitValue. E.g. "10" or "40mm" or "container.x2 - 10".
- * @return <code>this</code> so it is possible to chain calls. E.g. <code>new ComponentConstraint().noGrid().gap().fill()</code>.
- * @see #setPos(UnitValue[])
- * @see #setBoundsInGrid(boolean)
- */
- public final CC x2(String x2)
- {
- return corrPos(x2, 2);
- }
-
- /** Sets the y2-coordinate for the component (bottom side). This is used to set the y2 coordinate position to a specific value. The component
- * bounds is still precalculated to the grid cell and this method should be seen as a way to correct the y position.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @param y2 The y2 side's position as a UnitValue. E.g. "10" or "40mm" or "container.x2 - 10".
- * @return <code>this</code> so it is possible to chain calls. E.g. <code>new ComponentConstraint().noGrid().gap().fill()</code>.
- * @see #setPos(UnitValue[])
- * @see #setBoundsInGrid(boolean)
- */
- public final CC y2(String y2)
- {
- return corrPos(y2, 3);
- }
-
- private final CC corrPos(String uv, int ix)
- {
- UnitValue[] b = getPos();
- if (b == null)
- b = new UnitValue[4];
-
- b[ix] = ConstraintParser.parseUnitValue(uv, (ix % 2 == 0));
- setPos(b);
-
- setBoundsInGrid(true);
- return this;
- }
-
- /** Same functionality as {@link #x(String x)} and {@link #y(String y)} toghether.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @param x The x position as a UnitValue. E.g. "10" or "40mm" or "container.x+10".
- * @param y The y position as a UnitValue. E.g. "10" or "40mm" or "container.x+10".
- * @return <code>this</code> so it is possible to chain calls. E.g. <code>new ComponentConstraint().noGrid().gap().fill()</code>.
- * @see #setPos(UnitValue[])
- */
- public final CC pos(String x, String y)
- {
- UnitValue[] b = getPos();
- if (b == null)
- b = new UnitValue[4];
-
- b[0] = ConstraintParser.parseUnitValue(x, true);
- b[1] = ConstraintParser.parseUnitValue(y, false);
- setPos(b);
-
- setBoundsInGrid(false);
- return this;
- }
-
- /** Same functionality as {@link #x(String x)}, {@link #y(String y)}, {@link #y2(String y)} and {@link #y2(String y)} toghether.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @param x The x position as a UnitValue. E.g. "10" or "40mm" or "container.x+10".
- * @param y The y position as a UnitValue. E.g. "10" or "40mm" or "container.x+10".
- * @param x2 The x2 side's position as a UnitValue. E.g. "10" or "40mm" or "container.x2 - 10".
- * @param y2 The y2 side's position as a UnitValue. E.g. "10" or "40mm" or "container.x2 - 10".
- * @return <code>this</code> so it is possible to chain calls. E.g. <code>new ComponentConstraint().noGrid().gap().fill()</code>.
- * @see #setPos(UnitValue[])
- */
- public final CC pos(String x, String y, String x2, String y2)
- {
- setPos(new UnitValue[] {
- ConstraintParser.parseUnitValue(x, true),
- ConstraintParser.parseUnitValue(y, false),
- ConstraintParser.parseUnitValue(x2, true),
- ConstraintParser.parseUnitValue(y2, false),
- });
- setBoundsInGrid(false);
- return this;
- }
-
- /** Same functionality as {@link #setPadding(UnitValue[])} but the unit values as absolute pixels. This method returns <code>this</code> for chaining multiple calls.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @param top The top padding that will be added to the y coordinate at the last stage in the layout.
- * @param left The top padding that will be added to the x coordinate at the last stage in the layout.
- * @param bottom The top padding that will be added to the y2 coordinate at the last stage in the layout.
- * @param right The top padding that will be added to the x2 coordinate at the last stage in the layout.
- * @return <code>this</code> so it is possible to chain calls. E.g. <code>new ComponentConstraint().noGrid().gap().fill()</code>.
- * @see #setTag(String)
- */
- public final CC pad(int top, int left, int bottom, int right)
- {
- setPadding(new UnitValue[] {
- new UnitValue(top), new UnitValue(left), new UnitValue(bottom), new UnitValue(right)
- });
- return this;
- }
-
- /** Same functionality as <code>setPadding(ConstraintParser.parseInsets(pad, false))}</code> only this method returns <code>this</code> for chaining multiple calls.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @param pad The string to parse. E.g. "10 10 10 10" or "20". If less than 4 groups the last will be used for the missing.
- * @return <code>this</code> so it is possible to chain calls. E.g. <code>new ComponentConstraint().noGrid().gap().fill()</code>.
- * @see #setTag(String)
- */
- public final CC pad(String pad)
- {
- setPadding(pad != null ? ConstraintParser.parseInsets(pad, false) : null);
- return this;
- }
-
- // **********************************************************
- // Bean properties
- // **********************************************************
-
- /** Returns the horizontal dimension constraint for this component constraint. It has constraints for the horizontal size
- * and grow/shink priorities and weights.
- * @return The current dimension constraint. Never <code>null</code>.
- */
- public DimConstraint getHorizontal()
- {
- return hor;
- }
-
- /** Sets the horizontal dimension constraint for this component constraint. It has constraints for the horizontal size
- * and grow/shink priorities and weights.
- * @param h The new dimension constraint. If <code>null</code> it will be reset to <code>new DimConstraint();</code>
- */
- public void setHorizontal(DimConstraint h)
- {
- hor = h != null ? h : new DimConstraint();
- }
-
- /** Returns the vertical dimension constraint for this component constraint. It has constraints for the vertical size
- * and grow/shink priorities and weights.
- * @return The current dimension constraint. Never <code>null</code>.
- */
- public DimConstraint getVertical()
- {
- return ver;
- }
-
- /** Sets the vertical dimension constraint for this component constraint. It has constraints for the vertical size
- * and grow/shink priorities and weights.
- * @param v The new dimension constraint. If <code>null</code> it will be reset to <code>new DimConstraint();</code>
- */
- public void setVertical(DimConstraint v)
- {
- ver = v != null ? v : new DimConstraint();
- }
-
- /** Returns the vertical or horizontal dim constraint.
- * @param isHor If the horizontal constraint should be returned.
- * @return The dim constraint. Never <code>null</code>.
- */
- public DimConstraint getDimConstraint(boolean isHor)
- {
- return isHor ? hor : ver;
- }
-
- /** Returns the absolute positioning of one or more of the edges. This will be applied last in the layout cycle and will not
- * affect the flow or grid positions. The positioning is relative to the parent and can not (as padding) be used
- * to adjust the edges relative to the old value. May be <code>null</code> and elements may be <code>null</code>.
- * <code>null</code> value(s) for the x2 and y2 will be interpreted as to keep the preferred size and thus the x1
- * and x2 will just absolutely positions the component.
- * <p>
- * Note that {@link #setBoundsInGrid(boolean)} changes the interpretation of thisproperty slightly.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @return The current value as a new array, free to modify.
- */
- public UnitValue[] getPos()
- {
- return pos != null ? new UnitValue[] {pos[0], pos[1], pos[2], pos[3]} : null;
- }
-
- /** Sets absolute positioning of one or more of the edges. This will be applied last in the layout cycle and will not
- * affect the flow or grid positions. The positioning is relative to the parent and can not (as padding) be used
- * to adjust the edges relative to the old value. May be <code>null</code> and elements may be <code>null</code>.
- * <code>null</code> value(s) for the x2 and y2 will be interpreted as to keep the preferred size and thus the x1
- * and x2 will just absolutely positions the component.
- * <p>
- * Note that {@link #setBoundsInGrid(boolean)} changes the interpretation of thisproperty slightly.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @param pos <code>UnitValue[] {x, y, x2, y2}</code>. Must be <code>null</code> or of length 4. Elements can be <code>null</code>.
- */
- public void setPos(UnitValue[] pos)
- {
- this.pos = pos != null ? new UnitValue[] {pos[0], pos[1], pos[2], pos[3]} : null;
- }
-
- /** Returns if the absolute <code>pos</code> value should be corrections to the component that is in a normal cell. If <code>false</code>
- * the value of <code>pos</code> is truly absolute in that it will not affect the grid or have a default bounds in the grid.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @return The current value.
- * @see #getPos()
- */
- public boolean isBoundsInGrid()
- {
- return boundsInGrid;
- }
-
- /** Sets if the absolute <code>pos</code> value should be corrections to the component that is in a normal cell. If <code>false</code>
- * the value of <code>pos</code> is truly absolute in that it will not affect the grid or have a default bounds in the grid.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @param b <code>true</code> for bounds taken from the grid position. <code>false</code> is default.
- * @see #setPos(UnitValue[])
- */
- void setBoundsInGrid(boolean b)
- {
- this.boundsInGrid = b;
- }
-
- /** Returns the absolute cell position in the grid or <code>-1</code> if cell positioning is not used.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @return The current value.
- */
- public int getCellX()
- {
- return cellX;
- }
-
- /** Set an absolute cell x-position in the grid. If >= 0 this point points to the absolute cell that this constaint's component should occupy.
- * If there's already a component in that cell they will split the cell. The flow will then continue after this cell.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @param x The x-position or <code>-1</code> to disable cell positioning.
- */
- public void setCellX(int x)
- {
- cellX = x;
- }
-
- /** Returns the absolute cell position in the grid or <code>-1</code> if cell positioning is not used.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @return The current value.
- */
- public int getCellY()
- {
- return cellX < 0 ? -1 : cellY;
- }
-
- /** Set an absolute cell x-position in the grid. If >= 0 this point points to the absolute cell that this constaint's component should occupy.
- * If there's already a component in that cell they will split the cell. The flow will then continue after this cell.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @param y The y-position or <code>-1</code> to disable cell positioning.
- */
- public void setCellY(int y)
- {
- if (y < 0)
- cellX = -1;
- cellY = y < 0 ? 0 : y;
- }
-
- /** Sets the docking side. -1 means no docking.<br>
- * Valid sides are: <code> north = 0, west = 1, south = 2, east = 3</code>.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @return The current side.
- */
- public int getDockSide()
- {
- return dock;
- }
-
- /** Sets the docking side. -1 means no docking.<br>
- * Valid sides are: <code> north = 0, west = 1, south = 2, east = 3</code>.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @param side -1 or 0-3.
- */
- public void setDockSide(int side)
- {
- if (side < -1 || side > 3)
- throw new IllegalArgumentException("Illegal dock side: " + side);
- dock = side;
- }
-
- /** Returns if this component should have its bounds handled by an external source and not this layout manager.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @return The current value.
- */
- public boolean isExternal()
- {
- return external;
- }
-
- /** If this boolean is true this component is not handled in any way by the layout manager and the component can have its bounds set by an external
- * handler which is normally by the use of some <code>component.setBounds(x, y, width, height)</code> directly (for Swing).
- * <p>
- * The bounds <b>will not</b> affect the minimum and preferred size of the container.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @param b <code>true</code> means that the bounds are not changed.
- */
- public void setExternal(boolean b)
- {
- this.external = b;
- }
-
- /** Returns if the flow in the <b>cell</b> is in the horizontal dimension. Vertical if <code>false</code>. Only the first
- * component is a cell can set the flow.
- * <p>
- * If <code>null</code> the flow direction is inherited by from the {@link net.miginfocom.layout.LC}.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @return The current value.
- */
- public Boolean getFlowX()
- {
- return flowX;
- }
-
- /** Sets if the flow in the <b>cell</b> is in the horizontal dimension. Vertical if <code>false</code>. Only the first
- * component is a cell can set the flow.
- * <p>
- * If <code>null</code> the flow direction is inherited by from the {@link net.miginfocom.layout.LC}.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @param b <code>Boolean.TRUE</code> means horizontal flow in the cell.
- */
- public void setFlowX(Boolean b)
- {
- this.flowX = b;
- }
-
- /** Sets how a component that is hidden (not visible) should be treated by default.
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @return The mode:<br>
- * 0 == Normal. Bounds will be calculated as if the component was visible.<br>
- * 1 == If hidden the size will be 0, 0 but the gaps remain.<br>
- * 2 == If hidden the size will be 0, 0 and gaps set to zero.<br>
- * 3 == If hidden the component will be disregarded completely and not take up a cell in the grid..
- */
- public int getHideMode()
- {
- return hideMode;
- }
-
- /** Sets how a component that is hidden (not visible) should be treated by default.
- * @param mode The mode:<br>
- * 0 == Normal. Bounds will be calculated as if the component was visible.<br>
- * 1 == If hidden the size will be 0, 0 but the gaps remain.<br>
- * 2 == If hidden the size will be 0, 0 and gaps set to zero.<br>
- * 3 == If hidden the component will be disregarded completely and not take up a cell in the grid..
- */
- public void setHideMode(int mode)
- {
- if (mode < -1 || mode > 3)
- throw new IllegalArgumentException("Wrong hideMode: " + mode);
-
- hideMode = mode;
- }
-
- /** Returns the id used to reference this component in some constraints.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @return The id or <code>null</code>. May consist of a groupID and an componentID which are separated by a dot: ".". E.g. "grp1.id1".
- * The dot should never be first or last if present.
- */
- public String getId()
- {
- return id;
- }
-
- /** Sets the id used to reference this component in some constraints.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @param id The id or <code>null</code>. May consist of a groupID and an componentID which are separated by a dot: ".". E.g. "grp1.id1".
- * The dot should never be first or last if present.
- */
- public void setId(String id)
- {
- this.id = id;
- }
-
- /** Returns the absolute resizing in the last stage of the layout cycle. May be <code>null</code> and elements may be <code>null</code>.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @return The current value. <code>null</code> or of length 4.
- */
- public UnitValue[] getPadding()
- {
- return padding != null ? new UnitValue[] {padding[0], padding[1], padding[2], padding[3]} : null;
- }
-
- /** Sets the absolute resizing in the last stage of the layout cycle. These values are added to the edges and can thus for
- * instance be used to grow or reduce the size or move the component an absolute number of pixels. May be <code>null</code>
- * and elements may be <code>null</code>.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @param sides top, left, bottom right. Must be <code>null</code> or of length 4.
- */
- public void setPadding(UnitValue[] sides)
- {
- this.padding = sides != null ? new UnitValue[] {sides[0], sides[1], sides[2], sides[3]} : null;
- }
-
- /** Returns how many cells in the grid that should be skipped <b>before</b> the component that this constraint belongs to.
- * <p>
- * Note that only the first component will be checked for this property.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @return The current value. 0 if no skip.
- */
- public int getSkip()
- {
- return skip;
- }
-
- /** Sets how many cells in the grid that should be skipped <b>before</b> the component that this constraint belongs to.
- * <p>
- * Note that only the first component will be checked for this property.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @param cells How many cells in the grid that should be skipped <b>before</b> the component that this constraint belongs to
- */
- public void setSkip(int cells)
- {
- this.skip = cells;
- }
-
- /** Returns the number of cells the cell that this constraint's component will span in the indicated dimension. <code>1</code> is default and
- * means that it only spans the current cell. <code>LayoutUtil.INF</code> is used to indicate a span to the end of the column/row.
- * <p>
- * Note that only the first component will be checked for this property.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @return The current value.
- */
- public int getSpanX()
- {
- return spanX;
- }
-
- /** Sets the number of cells the cell that this constraint's component will span in the indicated dimension. <code>1</code> is default and
- * means that it only spans the current cell. <code>LayoutUtil.INF</code> is used to indicate a span to the end of the column/row.
- * <p>
- * Note that only the first component will be checked for this property.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @param cells The number of cells to span (i.e. merge).
- */
- public void setSpanX(int cells)
- {
- this.spanX = cells;
- }
-
- /** Returns the number of cells the cell that this constraint's component will span in the indicated dimension. <code>1</code> is default and
- * means that it only spans the current cell. <code>LayoutUtil.INF</code> is used to indicate a span to the end of the column/row.
- * <p>
- * Note that only the first component will be checked for this property.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @return The current value.
- */
- public int getSpanY()
- {
- return spanY;
- }
-
- /** Sets the number of cells the cell that this constraint's component will span in the indicated dimension. <code>1</code> is default and
- * means that it only spans the current cell. <code>LayoutUtil.INF</code> is used to indicate a span to the end of the column/row.
- * <p>
- * Note that only the first component will be checked for this property.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @param cells The number of cells to span (i.e. merge).
- */
- public void setSpanY(int cells)
- {
- this.spanY = cells;
- }
-
- /** "pushx" indicates that the column that this component is in (this first if the component spans) should default to growing.
- * If any other column has been set to grow this push value on the component does nothing as the column's explicit grow weight
- * will take precedence. Push is normally used when the grid has not been defined in the layout.
- * <p>
- * If multiple components in a column has push weights set the largest one will be used for the column.
- * @return The current push value. Default is <code>null</code>.
- */
- public Float getPushX()
- {
- return pushX;
- }
-
- /** "pushx" indicates that the column that this component is in (this first if the component spans) should default to growing.
- * If any other column has been set to grow this push value on the component does nothing as the column's explicit grow weight
- * will take precedence. Push is normally used when the grid has not been defined in the layout.
- * <p>
- * If multiple components in a column has push weights set the largest one will be used for the column.
- * @param weight The new push value. Default is <code>null</code>.
- */
- public void setPushX(Float weight)
- {
- this.pushX = weight;
- }
-
- /** "pushx" indicates that the row that this component is in (this first if the component spans) should default to growing.
- * If any other row has been set to grow this push value on the component does nothing as the row's explicit grow weight
- * will take precedence. Push is normally used when the grid has not been defined in the layout.
- * <p>
- * If multiple components in a row has push weights set the largest one will be used for the row.
- * @return The current push value. Default is <code>null</code>.
- */
- public Float getPushY()
- {
- return pushY;
- }
-
- /** "pushx" indicates that the row that this component is in (this first if the component spans) should default to growing.
- * If any other row has been set to grow this push value on the component does nothing as the row's explicit grow weight
- * will take precedence. Push is normally used when the grid has not been defined in the layout.
- * <p>
- * If multiple components in a row has push weights set the largest one will be used for the row.
- * @param weight The new push value. Default is <code>null</code>.
- */
- public void setPushY(Float weight)
- {
- this.pushY = weight;
- }
-
- /** Returns in how many parts the current cell (that this constraint's component will be in) should be split in. If for instance
- * it is split in two, the next componet will also share the same cell. Note that the cell can also span a number of
- * cells, which means that you can for instance span three cells and split that big cell for two components. Split can be
- * set to a very high value to make all components in the same row/column share the same cell (e.g. <code>LayoutUtil.INF</code>).
- * <p>
- * Note that only the first component will be checked for this property.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @return The current value.
- */
- public int getSplit()
- {
- return split;
- }
-
- /** Sets in how many parts the current cell (that this constraint's component will be in) should be split in. If for instance
- * it is split in two, the next componet will also share the same cell. Note that the cell can also span a number of
- * cells, which means that you can for instance span three cells and split that big cell for two components. Split can be
- * set to a very high value to make all components in the same row/column share the same cell (e.g. <code>LayoutUtil.INF</code>).
- * <p>
- * Note that only the first component will be checked for this property.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @param parts The number of parts (i.e. component slots) the cell should be divided into.
- */
- public void setSplit(int parts)
- {
- this.split = parts;
- }
-
- /** Tags the component with metadata. Currently only used to tag buttons with for instance "cancel" or "ok" to make them
- * show up in the correct order depending on platform. See {@link PlatformDefaults#setButtonOrder(String)} for information.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @return The current value. May be <code>null</code>.
- */
- public String getTag()
- {
- return tag;
- }
-
- /** Optinal tag that gives more context to this constraint's component. It is for instance used to tag buttons in a
- * button bar with the button type such as "ok", "help" or "cancel".
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @param tag The new tag. May be <code>null</code>.
- */
- public void setTag(String tag)
- {
- this.tag = tag;
- }
-
- /** Returns if the flow should wrap to the next line/column <b>after</b> the component that this constraint belongs to.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @return The current value.
- */
- public boolean isWrap()
- {
- return wrap != null;
- }
-
- /** Sets if the flow should wrap to the next line/column <b>after</b> the component that this constraint belongs to.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @param b <code>true</code> means wrap after.
- */
- public void setWrap(boolean b)
- {
- wrap = b ? (wrap == null ? DEF_GAP : wrap) : null;
- }
-
- /** Returns the wrap size if it is a custom size. If wrap was set to true with {@link #setWrap(boolean)} then this method will
- * return <code>null</code> since that means that the gap size should be the default one as defined in the rows spec.
- * @return The custom gap size. NOTE! Will return <code>null</code> for both no wrap <b>and</b> default wrap.
- * @see #isWrap()
- * @see #setWrap(boolean)
- * @since 2.4.2
- */
- public BoundSize getWrapGapSize()
- {
- return wrap == DEF_GAP ? null : wrap;
- }
-
- /** Set the wrap size and turns wrap on if <code>!= null</code>.
- * @param s The custom gap size. NOTE! <code>null</code> will not turn on or off wrap, it will only set the wrap gap size to "default".
- * A non-null value will turn on wrap though.
- * @see #isWrap()
- * @see #setWrap(boolean)
- * @since 2.4.2
- */
- public void setWrapGapSize(BoundSize s)
- {
- wrap = s == null ? (wrap != null ? DEF_GAP : null) : s;
- }
-
- /** Returns if the flow should wrap to the next line/column <b>before</b> the component that this constraint belongs to.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @return The current value.
- */
- public boolean isNewline()
- {
- return newline != null;
- }
-
- /** Sets if the flow should wrap to the next line/column <b>before</b> the component that this constraint belongs to.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @param b <code>true</code> means wrap before.
- */
- public void setNewline(boolean b)
- {
- newline = b ? (newline == null ? DEF_GAP : newline) : null;
- }
-
- /** Returns the newline size if it is a custom size. If newline was set to true with {@link #setNewline(boolean)} then this method will
- * return <code>null</code> since that means that the gap size should be the default one as defined in the rows spec.
- * @return The custom gap size. NOTE! Will return <code>null</code> for both no newline <b>and</b> default newline.
- * @see #isNewline()
- * @see #setNewline(boolean)
- * @since 2.4.2
- */
- public BoundSize getNewlineGapSize()
- {
- return newline == DEF_GAP ? null : newline;
- }
-
- /** Set the newline size and turns newline on if <code>!= null</code>.
- * @param s The custom gap size. NOTE! <code>null</code> will not turn on or off newline, it will only set the newline gap size to "default".
- * A non-null value will turn on newline though.
- * @see #isNewline()
- * @see #setNewline(boolean)
- * @since 2.4.2
- */
- public void setNewlineGapSize(BoundSize s)
- {
- newline = s == null ? (newline != null ? DEF_GAP : null) : s;
- }
-
- // ************************************************
- // Persistence Delegate and Serializable combined.
- // ************************************************
-
- private Object readResolve() throws ObjectStreamException
- {
- return LayoutUtil.getSerializedObject(this);
- }
-
- public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException
- {
- LayoutUtil.setSerializedObject(this, LayoutUtil.readAsXML(in));
- }
-
- public void writeExternal(ObjectOutput out) throws IOException
- {
- if (getClass() == CC.class)
- LayoutUtil.writeAsXML(out, this);
- }
+package net.miginfocom.layout; + +import java.io.*; +/* + * License (BSD): + * ============== + * + * Copyright (c) 2004, Mikael Grev, MiG InfoCom AB. (miglayout (at) miginfocom (dot) com) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright notice, this list + * of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * Neither the name of the MiG InfoCom AB nor the names of its contributors may be + * used to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * @version 1.0 + * @author Mikael Grev, MiG InfoCom AB + * Date: 2006-sep-08 + */ + +/** A simple value holder for one component's constraint. + */ +public final class CC implements Externalizable +{ + private static final BoundSize DEF_GAP = new BoundSize(null, null); // Only used to denote default wrap/newline gap. + + static final String[] DOCK_SIDES = {"north", "west", "south", "east"}; + + // See the getters and setters for information about the properties below. + + private int dock = -1; + + private UnitValue[] pos = null; // [x1, y1, x2, y2] + + private UnitValue[] padding = null; // top, left, bottom, right + + private Boolean flowX = null; + + private int skip = 0; + + private int split = 1; + + private int spanX = 1, spanY = 1; + + private int cellX = -1, cellY = 0; // If cellX is -1 then cellY is also considered -1. cellY is never negative. + + private String tag = null; + + private String id = null; + + private int hideMode = -1; + + private DimConstraint hor = new DimConstraint(); + + private DimConstraint ver = new DimConstraint(); + + private BoundSize newline = null; + + private BoundSize wrap = null; + + private boolean boundsInGrid = true; + + private boolean external = false; + + private Float pushX = null, pushY = null; + + + /** Empty constructor. + */ + public CC() + { + } + + // ********************************************************** + // Chaining constraint setters + // ********************************************************** + + /** Specifies that the component should be put in the end group <code>s</code> and will thus share the same ending + * coordinate as them within the group. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @param s A name to associate on the group that should be the same for other rows/columns in the same group. + * @return <code>this</code> so it is possible to chain calls. E.g. <code>new ComponentConstraint().noGrid().gap().fill()</code>. + */ + public final CC endGroupX(String s) + { + hor.setEndGroup(s); + return this; + } + + /** Specifies that the component should be put in the size group <code>s</code> and will thus share the same size + * as them within the group. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @param s A name to associate on the group that should be the same for other rows/columns in the same group. + * @return <code>this</code> so it is possible to chain calls. E.g. <code>new ComponentConstraint().noGrid().gap().fill()</code>. + */ + public final CC sizeGroupX(String s) + { + hor.setSizeGroup(s); + return this; + } + + /** The minimum size for the component. The value will override any value that is set on the component itself. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @param size The size expressed as a <code>UnitValue</code>. E.g. "100px" or "200mm". + * @return <code>this</code> so it is possible to chain calls. E.g. <code>new ComponentConstraint().noGrid().gap().fill()</code>. + */ + public final CC minWidth(String size) + { + hor.setSize(LayoutUtil.derive(hor.getSize(), ConstraintParser.parseUnitValue(size, true), null, null)); + return this; + } + + /** The size for the component as a min and/or preferref and/or maximum size. The value will override any value that is set on + * the component itself. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @param size The size expressed as a <code>BoundSize</code>. E.g. "50:100px:200mm" or "100px". + * @return <code>this</code> so it is possible to chain calls. E.g. <code>new ComponentConstraint().noGrid().gap().fill()</code>. + */ + public final CC width(String size) + { + hor.setSize(ConstraintParser.parseBoundSize(size, false, true)); + return this; + } + + /** The maximum size for the component. The value will override any value that is set on the component itself. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @param size The size expressed as a <code>UnitValue</code>. E.g. "100px" or "200mm". + * @return <code>this</code> so it is possible to chain calls. E.g. <code>new ComponentConstraint().noGrid().gap().fill()</code>. + */ + public final CC maxWidth(String size) + { + hor.setSize(LayoutUtil.derive(hor.getSize(), null, null, ConstraintParser.parseUnitValue(size, true))); + return this; + } + + + /** The horizontal gap before and/or after the component. The gap is towards cell bounds and/or other component bounds. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @param before The size of the gap expressed as a <code>BoundSize</code>. E.g. "50:100px:200mm" or "100px!". + * @param after The size of the gap expressed as a <code>BoundSize</code>. E.g. "50:100px:200mm" or "100px!". + * @return <code>this</code> so it is possible to chain calls. E.g. <code>new ComponentConstraint().noGrid().gap().fill()</code>. + */ + public final CC gapX(String before, String after) + { + if (before != null) + hor.setGapBefore(ConstraintParser.parseBoundSize(before, true, true)); + + if (after != null) + hor.setGapAfter(ConstraintParser.parseBoundSize(after, true, true)); + + return this; + } + + /** Same functionality as <code>getHorizontal().setAlign(ConstraintParser.parseUnitValue(unitValue, true))</code> only this method + * returns <code>this</code> for chaining multiple calls. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @param align The align keyword or for instance "100px". E.g "left", "right", "leading" or "trailing". + * @return <code>this</code> so it is possible to chain calls. E.g. <code>new ComponentConstraint().noGrid().gap().fill()</code>. + */ + public final CC alignX(String align) + { + hor.setAlign(ConstraintParser.parseUnitValueOrAlign(align, true, null)); + return this; + } + + /** The grow priority compared to other components in the same cell. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @param p The grow priority. + * @return <code>this</code> so it is possible to chain calls. E.g. <code>new ComponentConstraint().noGrid().gap().fill()</code>. + */ + public final CC growPrioX(int p) + { + hor.setGrowPriority(p); + return this; + } + + /** Grow weight for the component horizontally. It default to weight <code>100</code>. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @return <code>this</code> so it is possible to chain calls. E.g. <code>new ComponentConstraint().noGrid().gap().fill()</code>. + * @see #growX(float) + */ + public final CC growX() + { + hor.setGrow(ResizeConstraint.WEIGHT_100); + return this; + } + + /** Grow weight for the component horizontally. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @param w The new grow weight. + * @return <code>this</code> so it is possible to chain calls. E.g. <code>new ComponentConstraint().noGrid().gap().fill()</code>. + */ + public final CC growX(float w) + { + hor.setGrow(new Float(w)); + return this; + } + + /** The shrink priority compared to other components in the same cell. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @param p The shrink priority. + * @return <code>this</code> so it is possible to chain calls. E.g. <code>new ComponentConstraint().noGrid().gap().fill()</code>. + */ + public final CC shrinkPrioX(int p) + { + hor.setShrinkPriority(p); + return this; + } + + /** Shrink weight for the component horizontally. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @param w The new shrink weight. + * @return <code>this</code> so it is possible to chain calls. E.g. <code>new ComponentConstraint().noGrid().gap().fill()</code>. + */ + public final CC shrinkX(float w) + { + hor.setShrink(new Float(w)); + return this; + } + + /** The end group that this componet should be placed in. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @param s The name of the group. If <code>null</code> that means no group (default) + * @return <code>this</code> so it is possible to chain calls. E.g. <code>new ComponentConstraint().noGrid().gap().fill()</code>. + */ + public final CC endGroupY(String s) + { + ver.setEndGroup(s); + return this; + } + + /** The size group that this componet should be placed in. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @param s The name of the group. If <code>null</code> that means no group (default) + * @return <code>this</code> so it is possible to chain calls. E.g. <code>new ComponentConstraint().noGrid().gap().fill()</code>. + */ + public final CC sizeGroupY(String s) + { + ver.setSizeGroup(s); + return this; + } + + /** The minimum size for the component. The value will override any value that is set on the component itself. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @param size The size expressed as a <code>UnitValue</code>. E.g. "100px" or "200mm". + * @return <code>this</code> so it is possible to chain calls. E.g. <code>new ComponentConstraint().noGrid().gap().fill()</code>. + */ + public final CC minHeight(String size) + { + ver.setSize(LayoutUtil.derive(ver.getSize(), ConstraintParser.parseUnitValue(size, false), null, null)); + return this; + } + + /** The size for the component as a min and/or preferref and/or maximum size. The value will override any value that is set on + * the component itself. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @param size The size expressed as a <code>BoundSize</code>. E.g. "50:100px:200mm" or "100px". + * @return <code>this</code> so it is possible to chain calls. E.g. <code>new ComponentConstraint().noGrid().gap().fill()</code>. + */ + public final CC height(String size) + { + ver.setSize(ConstraintParser.parseBoundSize(size, false, false)); + return this; + } + + /** The maximum size for the component. The value will override any value that is set on the component itself. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @param size The size expressed as a <code>UnitValue</code>. E.g. "100px" or "200mm". + * @return <code>this</code> so it is possible to chain calls. E.g. <code>new ComponentConstraint().noGrid().gap().fill()</code>. + */ + public final CC maxHeight(String size) + { + ver.setSize(LayoutUtil.derive(ver.getSize(), null, null, ConstraintParser.parseUnitValue(size, false))); + return this; + } + + /** The vertical gap before (normally above) and/or after (normally below) the component. The gap is towards cell bounds and/or other component bounds. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @param before The size of the gap expressed as a <code>BoundSize</code>. E.g. "50:100px:200mm" or "100px!". + * @param after The size of the gap expressed as a <code>BoundSize</code>. E.g. "50:100px:200mm" or "100px!". + * @return <code>this</code> so it is possible to chain calls. E.g. <code>new ComponentConstraint().noGrid().gap().fill()</code>. + */ + public final CC gapY(String before, String after) + { + if (before != null) + ver.setGapBefore(ConstraintParser.parseBoundSize(before, true, false)); + + if (after != null) + ver.setGapAfter(ConstraintParser.parseBoundSize(after, true, false)); + + return this; + } + + /** Same functionality as <code>getVertical().setAlign(ConstraintParser.parseUnitValue(unitValue, true))</code> only this method + * returns <code>this</code> for chaining multiple calls. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @param align The align keyword or for instance "100px". E.g "top" or "bottom". + * @return <code>this</code> so it is possible to chain calls. E.g. <code>new ComponentConstraint().noGrid().gap().fill()</code>. + */ + public final CC alignY(String align) + { + ver.setAlign(ConstraintParser.parseUnitValueOrAlign(align, false, null)); + return this; + } + + /** The grow priority compared to other components in the same cell. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @param p The grow priority. + * @return <code>this</code> so it is possible to chain calls. E.g. <code>new ComponentConstraint().noGrid().gap().fill()</code>. + */ + public final CC growPrioY(int p) + { + ver.setGrowPriority(p); + return this; + } + + /** Grow weight for the component vertically. Defaults to <code>100</code>. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @return <code>this</code> so it is possible to chain calls. E.g. <code>new ComponentConstraint().noGrid().gap().fill()</code>. + * @see #growY(Float) + */ + public final CC growY() + { + ver.setGrow(ResizeConstraint.WEIGHT_100); + return this; + } + + /** Grow weight for the component vertically. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @param w The new grow weight. + * @return <code>this</code> so it is possible to chain calls. E.g. <code>new ComponentConstraint().noGrid().gap().fill()</code>. + */ + public final CC growY(Float w) + { + ver.setGrow(w); + return this; + } + + /** The shrink priority compared to other components in the same cell. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @param p The shrink priority. + * @return <code>this</code> so it is possible to chain calls. E.g. <code>new ComponentConstraint().noGrid().gap().fill()</code>. + */ + public final CC shrinkPrioY(int p) + { + ver.setShrinkPriority(p); + return this; + } + + /** Shrink weight for the component horizontally. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @param w The new shrink weight. + * @return <code>this</code> so it is possible to chain calls. E.g. <code>new ComponentConstraint().noGrid().gap().fill()</code>. + */ + public final CC shrinkY(float w) + { + ver.setShrink(new Float(w)); + return this; + } + + /** How this component, if hidden (not visible), should be treated. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @param mode The mode. Default to the mode in the {@link net.miginfocom.layout.LC}. + * 0 == Normal. Bounds will be calculated as if the component was visible.<br> + * 1 == If hidden the size will be 0, 0 but the gaps remain.<br> + * 2 == If hidden the size will be 0, 0 and gaps set to zero.<br> + * 3 == If hidden the component will be disregarded completely and not take up a cell in the grid.. + * @return <code>this</code> so it is possible to chain calls. E.g. <code>new ComponentConstraint().noGrid().gap().fill()</code>. + */ + public final CC hideMode(int mode) + { + setHideMode(mode); + return this; + } + + /** The id used to reference this component in some constraints. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @param s The id or <code>null</code>. May consist of a groupID and an componentID which are separated by a dot: ".". E.g. "grp1.id1". + * The dot should never be first or last if present. + * @return <code>this</code> so it is possible to chain calls. E.g. <code>new ComponentConstraint().noGrid().gap().fill()</code>. + */ + public final CC id(String s) + { + setId(s); + return this; + } + + /** Same functionality as {@link #setTag(String tag)} only this method returns <code>this</code> for chaining multiple calls. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @param tag The new tag. May be <code>null</code>. + * @return <code>this</code> so it is possible to chain calls. E.g. <code>new LayoutConstraint().noGrid().gap().fill()</code>. + * @see #setTag(String) + */ + public final CC tag(String tag) + { + setTag(tag); + return this; + } + + /** Same functionality as {@link #setCellX(int col)} and {@link #setCellY(int row)} only this method returns <code>this</code> for chaining multiple calls. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @param col The column in the grid to place this component. + * @param row The rw in the grid to place this component. + * @return <code>this</code> so it is possible to chain calls. E.g. <code>new LayoutConstraint().noGrid().gap().fill()</code>. + * @see #setCellX(int) + * @see #setCellY(int) + */ + public final CC cell(int col, int row) + { + setCellX(col); + setCellY(row); + return this; + } + + /** Set the cell(s) that the component should occupy in the grid. Same functionality as {@link #setCellX(int col)} and + * {@link #setCellY(int row)} together with {@link #setSpanX(int width)} and {@link #setSpanY(int height)}. This method + * returns <code>this</code> for chaining multiple calls. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @param col The column in the grid to place this component. + * @param row The rw in the grid to place this component. + * @param width How many cells the component should span (i.e. merge). <code>LayoutUtil.INF</code> spans to the end of the row. + * @param height How many cells the component should span (i.e. merge). <code>LayoutUtil.INF</code> spans to the end of the column. + * @return <code>this</code> so it is possible to chain calls. E.g. <code>new LayoutConstraint().noGrid().gap().fill()</code>. + * @see #setCellX(int) + * @see #setCellY(int) + */ + public final CC cell(int col, int row, int width, int height) + { + setCellX(col); + setCellY(row); + setSpanX(width); + setSpanY(height); + return this; + } + + /** Same functionality as <code>spanX(cellsX).spanY(cellsY)</code> which means this cell will span cells in both x and y. + * This method returns <code>this</code> for chaining multiple calls. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @return <code>this</code> so it is possible to chain calls. E.g. <code>new LayoutConstraint().noGrid().gap().fill()</code>. + * @see #setSpanY(int) + * @see #setSpanX(int) + * @see #spanY() + * @see #spanX() + */ + public final CC span(int cellsX, int cellsY) + { + return spanX(cellsX).spanY(cellsY); + } + + /** Same functionality as {@link #setSpanY(int LayoutUtil.INF)} which means this cell will span the rest of the column. + * This method returns <code>this</code> for chaining multiple calls. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @return <code>this</code> so it is possible to chain calls. E.g. <code>new LayoutConstraint().noGrid().gap().fill()</code>. + * @see #setSpanY(int) + * @see #spanY() + */ + public final CC spanY() + { + return spanY(LayoutUtil.INF); + } + + /** Same functionality as {@link #setSpanY(int cells)} only this method returns <code>this</code> for chaining multiple calls. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @param cells The number of cells to span (i.e. merge). + * @return <code>this</code> so it is possible to chain calls. E.g. <code>new LayoutConstraint().noGrid().gap().fill()</code>. + * @see #setSpanY(int) + */ + public final CC spanY(int cells) + { + setSpanY(cells); + return this; + } + + /** Same functionality as {@link #setSpanX(int LayoutUtil.INF)} which means this cell will span the rest of the row. + * This method returns <code>this</code> for chaining multiple calls. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @return <code>this</code> so it is possible to chain calls. E.g. <code>new LayoutConstraint().noGrid().gap().fill()</code>. + * @see #setSpanX(int) + * @see #spanX() + */ + public final CC spanX() + { + return spanX(LayoutUtil.INF); + } + + /** Same functionality as {@link #setSpanX(int cells)} only this method returns <code>this</code> for chaining multiple calls. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @param cells The number of cells to span (i.e. merge). + * @return <code>this</code> so it is possible to chain calls. E.g. <code>new LayoutConstraint().noGrid().gap().fill()</code>. + * @see #setSpanY(int) + */ + public final CC spanX(int cells) + { + setSpanX(cells); + return this; + } + + /** Same functionality as <code>pushX().pushY()</code> which means this cell will push in both x and y dimensions. + * This method returns <code>this</code> for chaining multiple calls. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @return <code>this</code> so it is possible to chain calls. E.g. <code>new LayoutConstraint().noGrid().gap().fill()</code>. + * @see #setPushX(Float) + * @see #setPushX(Float) + * @see #pushY() + * @see #pushX() + */ + public final CC push() + { + return pushX().pushY(); + } + + /** Same functionality as <code>pushX(weightX).pushY(weightY)</code> which means this cell will push in both x and y dimensions. + * This method returns <code>this</code> for chaining multiple calls. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @param weightX The weight used in the push. + * @param weightY The weight used in the push. + * @return <code>this</code> so it is possible to chain calls. E.g. <code>new LayoutConstraint().noGrid().gap().fill()</code>. + * @see #setPushY(Float) + * @see #setPushX(Float) + * @see #pushY() + * @see #pushX() + */ + public final CC push(Float weightX, Float weightY) + { + return pushX(weightX).pushY(weightY); + } + + /** Same functionality as {@link #setPushY(Float))} which means this cell will push the rest of the column. + * This method returns <code>this</code> for chaining multiple calls. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @return <code>this</code> so it is possible to chain calls. E.g. <code>new LayoutConstraint().noGrid().gap().fill()</code>. + * @see #setPushY(Float) + * @see #pushY() + */ + public final CC pushY() + { + return pushY(ResizeConstraint.WEIGHT_100); + } + + /** Same functionality as {@link #setPushY(Float weight)} only this method returns <code>this</code> for chaining multiple calls. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @param weight The weight used in the push. + * @return <code>this</code> so it is possible to chain calls. E.g. <code>new LayoutConstraint().noGrid().gap().fill()</code>. + * @see #setPushY(Float) + */ + public final CC pushY(Float weight) + { + setPushY(weight); + return this; + } + + /** Same functionality as {@link #setPushX(Float)} which means this cell will push the rest of the row. + * This method returns <code>this</code> for chaining multiple calls. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @return <code>this</code> so it is possible to chain calls. E.g. <code>new LayoutConstraint().noGrid().gap().fill()</code>. + * @see #setPushX(Float) + * @see #pushX() + */ + public final CC pushX() + { + return pushX(ResizeConstraint.WEIGHT_100); + } + + /** Same functionality as {@link #setPushX(Float weight)} only this method returns <code>this</code> for chaining multiple calls. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @param weight The weight used in the push. + * @return <code>this</code> so it is possible to chain calls. E.g. <code>new LayoutConstraint().noGrid().gap().fill()</code>. + * @see #setPushY(Float) + */ + public final CC pushX(Float weight) + { + setPushX(weight); + return this; + } + + /** Same functionality as {@link #setSplit(int parts)} only this method returns <code>this</code> for chaining multiple calls. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @param parts The number of parts (i.e. component slots) the cell should be divided into. + * @return <code>this</code> so it is possible to chain calls. E.g. <code>new ComponentConstraint().noGrid().gap().fill()</code>. + * @see #setSplit(int) + */ + public final CC split(int parts) + { + setSplit(parts); + return this; + } + + /** Same functionality as {@link #setSkip(int)} only this method returns <code>this</code> for chaining multiple calls. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @param cells How many cells in the grid that should be skipped <b>before</b> the component that this constraint belongs to + * @return <code>this</code> so it is possible to chain calls. E.g. <code>new ComponentConstraint().noGrid().gap().fill()</code>. + * @see #setSkip(int) + */ + public final CC skip(int cells) + { + setSkip(cells); + return this; + } + + /** Same functionality as {@link #setExternal(boolean true)} only this method returns <code>this</code> for chaining multiple calls. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @return <code>this</code> so it is possible to chain calls. E.g. <code>new ComponentConstraint().noGrid().gap().fill()</code>. + * @see #setExternal(boolean) + */ + public final CC external() + { + setExternal(true); + return this; + } + + /** Same functionality as {@link #setFlowX(Boolean .TRUE)} only this method returns <code>this</code> for chaining multiple calls. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @return <code>this</code> so it is possible to chain calls. E.g. <code>new ComponentConstraint().noGrid().gap().fill()</code>. + * @see #setFlowX(Boolean) + */ + public final CC flowX() + { + setFlowX(Boolean.TRUE); + return this; + } + + /** Same functionality as {@link #setFlowX(Boolean .FALSE)} only this method returns <code>this</code> for chaining multiple calls. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @return <code>this</code> so it is possible to chain calls. E.g. <code>new ComponentConstraint().noGrid().gap().fill()</code>. + * @see #setFlowX(Boolean) + */ + public final CC flowY() + { + setFlowX(Boolean.FALSE); + return this; + } + + + /** Same functionality as {@link #growX()} and {@link #growY()}. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @return <code>this</code> so it is possible to chain calls. E.g. <code>new ComponentConstraint().noGrid().gap().fill()</code>. + * @see #growX() + * @see #growY() + */ + public final CC grow() + { + growX(); + growY(); + return this; + } + + /** Same functionality as {@link #setNewline(boolean true)} only this method returns <code>this</code> for chaining multiple calls. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @return <code>this</code> so it is possible to chain calls. E.g. <code>new ComponentConstraint().noGrid().gap().fill()</code>. + * @see #setNewline(boolean) + */ + public final CC newline() + { + setNewline(true); + return this; + } + + /** Same functionality as {@link #setNewlineGapSize(BoundString)} only this method returns <code>this</code> for chaining multiple calls. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @param gapSize The gap size that will override the gap size in the row/colum constraints if <code>!= null</code>. E.g. "5px" or "unrel". + * If <code>null</code> or <code>""</code> the newline size will be set to the default size and turned on. This is different compared to + * {@link #setNewlineGapSize(BoundString)}. + * @return <code>this</code> so it is possible to chain calls. E.g. <code>new ComponentConstraint().noGrid().gap().fill()</code>. + * @see #setNewlineGapSize(BoundSize) + */ + public final CC newline(String gapSize) + { + BoundSize bs = ConstraintParser.parseBoundSize(gapSize, true, (flowX != null && flowX == false)); + if (bs != null) { + setNewlineGapSize(bs); + } else { + setNewline(true); + } + return this; + } + + /** Same functionality as {@link #setWrap(boolean true)} only this method returns <code>this</code> for chaining multiple calls. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @return <code>this</code> so it is possible to chain calls. E.g. <code>new ComponentConstraint().noGrid().gap().fill()</code>. + * @see #setWrap(boolean) + */ + public final CC wrap() + { + setWrap(true); + return this; + } + + /** Same functionality as {@link #setWrapGapSize(BoundString)} only this method returns <code>this</code> for chaining multiple calls. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @param gapSize The gap size that will override the gap size in the row/colum constraints if <code>!= null</code>. E.g. "5px" or "unrel". + * If <code>null</code> or <code>""</code> the wrap size will be set to the default size and turned on. This is different compared to + * {@link #setWrapGapSize(BoundString)}. + * @return <code>this</code> so it is possible to chain calls. E.g. <code>new ComponentConstraint().noGrid().gap().fill()</code>. + * @see #setWrapGapSize(BoundSize) + */ + public final CC wrap(String gapSize) + { + BoundSize bs = ConstraintParser.parseBoundSize(gapSize, true, (flowX != null && flowX == false)); + if (bs != null) { + setWrapGapSize(bs); + } else { + setWrap(true); + } + return this; + } + + /** Same functionality as {@link #setDockSide(int 0)} only this method returns <code>this</code> for chaining multiple calls. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @return <code>this</code> so it is possible to chain calls. E.g. <code>new ComponentConstraint().noGrid().gap().fill()</code>. + * @see #setDockSide(int) + */ + public final CC dockNorth() + { + setDockSide(0); + return this; + } + + /** Same functionality as {@link #setDockSide(int 1)} only this method returns <code>this</code> for chaining multiple calls. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @return <code>this</code> so it is possible to chain calls. E.g. <code>new ComponentConstraint().noGrid().gap().fill()</code>. + * @see #setDockSide(int) + */ + public final CC dockWest() + { + setDockSide(1); + return this; + } + + /** Same functionality as {@link #setDockSide(int 2)} only this method returns <code>this</code> for chaining multiple calls. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @return <code>this</code> so it is possible to chain calls. E.g. <code>new ComponentConstraint().noGrid().gap().fill()</code>. + * @see #setDockSide(int) + */ + public final CC dockSouth() + { + setDockSide(2); + return this; + } + + /** Same functionality as {@link #setDockSide(int 3)} only this method returns <code>this</code> for chaining multiple calls. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @return <code>this</code> so it is possible to chain calls. E.g. <code>new ComponentConstraint().noGrid().gap().fill()</code>. + * @see #setDockSide(int) + */ + public final CC dockEast() + { + setDockSide(3); + return this; + } + + /** Sets the x-coordinate for the component. This is used to set the x coordinate position to a specific value. The component + * bounds is still precalculated to the grid cell and this method should be seen as a way to correct the x position. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @param x The x position as a UnitValue. E.g. "10" or "40mm" or "container.x+10". + * @return <code>this</code> so it is possible to chain calls. E.g. <code>new ComponentConstraint().noGrid().gap().fill()</code>. + * @see #setPos(UnitValue[]) + * @see #setBoundsInGrid(boolean) + */ + public final CC x(String x) + { + return corrPos(x, 0); + } + + /** Sets the y-coordinate for the component. This is used to set the y coordinate position to a specific value. The component + * bounds is still precalculated to the grid cell and this method should be seen as a way to correct the y position. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @param y The y position as a UnitValue. E.g. "10" or "40mm" or "container.x+10". + * @return <code>this</code> so it is possible to chain calls. E.g. <code>new ComponentConstraint().noGrid().gap().fill()</code>. + * @see #setPos(UnitValue[]) + * @see #setBoundsInGrid(boolean) + */ + public final CC y(String y) + { + return corrPos(y, 1); + } + + /** Sets the x2-coordinate for the component (right side). This is used to set the x2 coordinate position to a specific value. The component + * bounds is still precalculated to the grid cell and this method should be seen as a way to correct the x position. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @param x2 The x2 side's position as a UnitValue. E.g. "10" or "40mm" or "container.x2 - 10". + * @return <code>this</code> so it is possible to chain calls. E.g. <code>new ComponentConstraint().noGrid().gap().fill()</code>. + * @see #setPos(UnitValue[]) + * @see #setBoundsInGrid(boolean) + */ + public final CC x2(String x2) + { + return corrPos(x2, 2); + } + + /** Sets the y2-coordinate for the component (bottom side). This is used to set the y2 coordinate position to a specific value. The component + * bounds is still precalculated to the grid cell and this method should be seen as a way to correct the y position. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @param y2 The y2 side's position as a UnitValue. E.g. "10" or "40mm" or "container.x2 - 10". + * @return <code>this</code> so it is possible to chain calls. E.g. <code>new ComponentConstraint().noGrid().gap().fill()</code>. + * @see #setPos(UnitValue[]) + * @see #setBoundsInGrid(boolean) + */ + public final CC y2(String y2) + { + return corrPos(y2, 3); + } + + private final CC corrPos(String uv, int ix) + { + UnitValue[] b = getPos(); + if (b == null) + b = new UnitValue[4]; + + b[ix] = ConstraintParser.parseUnitValue(uv, (ix % 2 == 0)); + setPos(b); + + setBoundsInGrid(true); + return this; + } + + /** Same functionality as {@link #x(String x)} and {@link #y(String y)} toghether. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @param x The x position as a UnitValue. E.g. "10" or "40mm" or "container.x+10". + * @param y The y position as a UnitValue. E.g. "10" or "40mm" or "container.x+10". + * @return <code>this</code> so it is possible to chain calls. E.g. <code>new ComponentConstraint().noGrid().gap().fill()</code>. + * @see #setPos(UnitValue[]) + */ + public final CC pos(String x, String y) + { + UnitValue[] b = getPos(); + if (b == null) + b = new UnitValue[4]; + + b[0] = ConstraintParser.parseUnitValue(x, true); + b[1] = ConstraintParser.parseUnitValue(y, false); + setPos(b); + + setBoundsInGrid(false); + return this; + } + + /** Same functionality as {@link #x(String x)}, {@link #y(String y)}, {@link #y2(String y)} and {@link #y2(String y)} toghether. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @param x The x position as a UnitValue. E.g. "10" or "40mm" or "container.x+10". + * @param y The y position as a UnitValue. E.g. "10" or "40mm" or "container.x+10". + * @param x2 The x2 side's position as a UnitValue. E.g. "10" or "40mm" or "container.x2 - 10". + * @param y2 The y2 side's position as a UnitValue. E.g. "10" or "40mm" or "container.x2 - 10". + * @return <code>this</code> so it is possible to chain calls. E.g. <code>new ComponentConstraint().noGrid().gap().fill()</code>. + * @see #setPos(UnitValue[]) + */ + public final CC pos(String x, String y, String x2, String y2) + { + setPos(new UnitValue[] { + ConstraintParser.parseUnitValue(x, true), + ConstraintParser.parseUnitValue(y, false), + ConstraintParser.parseUnitValue(x2, true), + ConstraintParser.parseUnitValue(y2, false), + }); + setBoundsInGrid(false); + return this; + } + + /** Same functionality as {@link #setPadding(UnitValue[])} but the unit values as absolute pixels. This method returns <code>this</code> for chaining multiple calls. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @param top The top padding that will be added to the y coordinate at the last stage in the layout. + * @param left The top padding that will be added to the x coordinate at the last stage in the layout. + * @param bottom The top padding that will be added to the y2 coordinate at the last stage in the layout. + * @param right The top padding that will be added to the x2 coordinate at the last stage in the layout. + * @return <code>this</code> so it is possible to chain calls. E.g. <code>new ComponentConstraint().noGrid().gap().fill()</code>. + * @see #setTag(String) + */ + public final CC pad(int top, int left, int bottom, int right) + { + setPadding(new UnitValue[] { + new UnitValue(top), new UnitValue(left), new UnitValue(bottom), new UnitValue(right) + }); + return this; + } + + /** Same functionality as <code>setPadding(ConstraintParser.parseInsets(pad, false))}</code> only this method returns <code>this</code> for chaining multiple calls. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @param pad The string to parse. E.g. "10 10 10 10" or "20". If less than 4 groups the last will be used for the missing. + * @return <code>this</code> so it is possible to chain calls. E.g. <code>new ComponentConstraint().noGrid().gap().fill()</code>. + * @see #setTag(String) + */ + public final CC pad(String pad) + { + setPadding(pad != null ? ConstraintParser.parseInsets(pad, false) : null); + return this; + } + + // ********************************************************** + // Bean properties + // ********************************************************** + + /** Returns the horizontal dimension constraint for this component constraint. It has constraints for the horizontal size + * and grow/shink priorities and weights. + * @return The current dimension constraint. Never <code>null</code>. + */ + public DimConstraint getHorizontal() + { + return hor; + } + + /** Sets the horizontal dimension constraint for this component constraint. It has constraints for the horizontal size + * and grow/shink priorities and weights. + * @param h The new dimension constraint. If <code>null</code> it will be reset to <code>new DimConstraint();</code> + */ + public void setHorizontal(DimConstraint h) + { + hor = h != null ? h : new DimConstraint(); + } + + /** Returns the vertical dimension constraint for this component constraint. It has constraints for the vertical size + * and grow/shink priorities and weights. + * @return The current dimension constraint. Never <code>null</code>. + */ + public DimConstraint getVertical() + { + return ver; + } + + /** Sets the vertical dimension constraint for this component constraint. It has constraints for the vertical size + * and grow/shink priorities and weights. + * @param v The new dimension constraint. If <code>null</code> it will be reset to <code>new DimConstraint();</code> + */ + public void setVertical(DimConstraint v) + { + ver = v != null ? v : new DimConstraint(); + } + + /** Returns the vertical or horizontal dim constraint. + * @param isHor If the horizontal constraint should be returned. + * @return The dim constraint. Never <code>null</code>. + */ + public DimConstraint getDimConstraint(boolean isHor) + { + return isHor ? hor : ver; + } + + /** Returns the absolute positioning of one or more of the edges. This will be applied last in the layout cycle and will not + * affect the flow or grid positions. The positioning is relative to the parent and can not (as padding) be used + * to adjust the edges relative to the old value. May be <code>null</code> and elements may be <code>null</code>. + * <code>null</code> value(s) for the x2 and y2 will be interpreted as to keep the preferred size and thus the x1 + * and x2 will just absolutely positions the component. + * <p> + * Note that {@link #setBoundsInGrid(boolean)} changes the interpretation of thisproperty slightly. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @return The current value as a new array, free to modify. + */ + public UnitValue[] getPos() + { + return pos != null ? new UnitValue[] {pos[0], pos[1], pos[2], pos[3]} : null; + } + + /** Sets absolute positioning of one or more of the edges. This will be applied last in the layout cycle and will not + * affect the flow or grid positions. The positioning is relative to the parent and can not (as padding) be used + * to adjust the edges relative to the old value. May be <code>null</code> and elements may be <code>null</code>. + * <code>null</code> value(s) for the x2 and y2 will be interpreted as to keep the preferred size and thus the x1 + * and x2 will just absolutely positions the component. + * <p> + * Note that {@link #setBoundsInGrid(boolean)} changes the interpretation of thisproperty slightly. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @param pos <code>UnitValue[] {x, y, x2, y2}</code>. Must be <code>null</code> or of length 4. Elements can be <code>null</code>. + */ + public void setPos(UnitValue[] pos) + { + this.pos = pos != null ? new UnitValue[] {pos[0], pos[1], pos[2], pos[3]} : null; + } + + /** Returns if the absolute <code>pos</code> value should be corrections to the component that is in a normal cell. If <code>false</code> + * the value of <code>pos</code> is truly absolute in that it will not affect the grid or have a default bounds in the grid. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @return The current value. + * @see #getPos() + */ + public boolean isBoundsInGrid() + { + return boundsInGrid; + } + + /** Sets if the absolute <code>pos</code> value should be corrections to the component that is in a normal cell. If <code>false</code> + * the value of <code>pos</code> is truly absolute in that it will not affect the grid or have a default bounds in the grid. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @param b <code>true</code> for bounds taken from the grid position. <code>false</code> is default. + * @see #setPos(UnitValue[]) + */ + void setBoundsInGrid(boolean b) + { + this.boundsInGrid = b; + } + + /** Returns the absolute cell position in the grid or <code>-1</code> if cell positioning is not used. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @return The current value. + */ + public int getCellX() + { + return cellX; + } + + /** Set an absolute cell x-position in the grid. If >= 0 this point points to the absolute cell that this constaint's component should occupy. + * If there's already a component in that cell they will split the cell. The flow will then continue after this cell. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @param x The x-position or <code>-1</code> to disable cell positioning. + */ + public void setCellX(int x) + { + cellX = x; + } + + /** Returns the absolute cell position in the grid or <code>-1</code> if cell positioning is not used. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @return The current value. + */ + public int getCellY() + { + return cellX < 0 ? -1 : cellY; + } + + /** Set an absolute cell x-position in the grid. If >= 0 this point points to the absolute cell that this constaint's component should occupy. + * If there's already a component in that cell they will split the cell. The flow will then continue after this cell. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @param y The y-position or <code>-1</code> to disable cell positioning. + */ + public void setCellY(int y) + { + if (y < 0) + cellX = -1; + cellY = y < 0 ? 0 : y; + } + + /** Sets the docking side. -1 means no docking.<br> + * Valid sides are: <code> north = 0, west = 1, south = 2, east = 3</code>. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @return The current side. + */ + public int getDockSide() + { + return dock; + } + + /** Sets the docking side. -1 means no docking.<br> + * Valid sides are: <code> north = 0, west = 1, south = 2, east = 3</code>. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @param side -1 or 0-3. + */ + public void setDockSide(int side) + { + if (side < -1 || side > 3) + throw new IllegalArgumentException("Illegal dock side: " + side); + dock = side; + } + + /** Returns if this component should have its bounds handled by an external source and not this layout manager. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @return The current value. + */ + public boolean isExternal() + { + return external; + } + + /** If this boolean is true this component is not handled in any way by the layout manager and the component can have its bounds set by an external + * handler which is normally by the use of some <code>component.setBounds(x, y, width, height)</code> directly (for Swing). + * <p> + * The bounds <b>will not</b> affect the minimum and preferred size of the container. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @param b <code>true</code> means that the bounds are not changed. + */ + public void setExternal(boolean b) + { + this.external = b; + } + + /** Returns if the flow in the <b>cell</b> is in the horizontal dimension. Vertical if <code>false</code>. Only the first + * component is a cell can set the flow. + * <p> + * If <code>null</code> the flow direction is inherited by from the {@link net.miginfocom.layout.LC}. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @return The current value. + */ + public Boolean getFlowX() + { + return flowX; + } + + /** Sets if the flow in the <b>cell</b> is in the horizontal dimension. Vertical if <code>false</code>. Only the first + * component is a cell can set the flow. + * <p> + * If <code>null</code> the flow direction is inherited by from the {@link net.miginfocom.layout.LC}. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @param b <code>Boolean.TRUE</code> means horizontal flow in the cell. + */ + public void setFlowX(Boolean b) + { + this.flowX = b; + } + + /** Sets how a component that is hidden (not visible) should be treated by default. + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @return The mode:<br> + * 0 == Normal. Bounds will be calculated as if the component was visible.<br> + * 1 == If hidden the size will be 0, 0 but the gaps remain.<br> + * 2 == If hidden the size will be 0, 0 and gaps set to zero.<br> + * 3 == If hidden the component will be disregarded completely and not take up a cell in the grid.. + */ + public int getHideMode() + { + return hideMode; + } + + /** Sets how a component that is hidden (not visible) should be treated by default. + * @param mode The mode:<br> + * 0 == Normal. Bounds will be calculated as if the component was visible.<br> + * 1 == If hidden the size will be 0, 0 but the gaps remain.<br> + * 2 == If hidden the size will be 0, 0 and gaps set to zero.<br> + * 3 == If hidden the component will be disregarded completely and not take up a cell in the grid.. + */ + public void setHideMode(int mode) + { + if (mode < -1 || mode > 3) + throw new IllegalArgumentException("Wrong hideMode: " + mode); + + hideMode = mode; + } + + /** Returns the id used to reference this component in some constraints. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @return The id or <code>null</code>. May consist of a groupID and an componentID which are separated by a dot: ".". E.g. "grp1.id1". + * The dot should never be first or last if present. + */ + public String getId() + { + return id; + } + + /** Sets the id used to reference this component in some constraints. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @param id The id or <code>null</code>. May consist of a groupID and an componentID which are separated by a dot: ".". E.g. "grp1.id1". + * The dot should never be first or last if present. + */ + public void setId(String id) + { + this.id = id; + } + + /** Returns the absolute resizing in the last stage of the layout cycle. May be <code>null</code> and elements may be <code>null</code>. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @return The current value. <code>null</code> or of length 4. + */ + public UnitValue[] getPadding() + { + return padding != null ? new UnitValue[] {padding[0], padding[1], padding[2], padding[3]} : null; + } + + /** Sets the absolute resizing in the last stage of the layout cycle. These values are added to the edges and can thus for + * instance be used to grow or reduce the size or move the component an absolute number of pixels. May be <code>null</code> + * and elements may be <code>null</code>. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @param sides top, left, bottom right. Must be <code>null</code> or of length 4. + */ + public void setPadding(UnitValue[] sides) + { + this.padding = sides != null ? new UnitValue[] {sides[0], sides[1], sides[2], sides[3]} : null; + } + + /** Returns how many cells in the grid that should be skipped <b>before</b> the component that this constraint belongs to. + * <p> + * Note that only the first component will be checked for this property. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @return The current value. 0 if no skip. + */ + public int getSkip() + { + return skip; + } + + /** Sets how many cells in the grid that should be skipped <b>before</b> the component that this constraint belongs to. + * <p> + * Note that only the first component will be checked for this property. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @param cells How many cells in the grid that should be skipped <b>before</b> the component that this constraint belongs to + */ + public void setSkip(int cells) + { + this.skip = cells; + } + + /** Returns the number of cells the cell that this constraint's component will span in the indicated dimension. <code>1</code> is default and + * means that it only spans the current cell. <code>LayoutUtil.INF</code> is used to indicate a span to the end of the column/row. + * <p> + * Note that only the first component will be checked for this property. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @return The current value. + */ + public int getSpanX() + { + return spanX; + } + + /** Sets the number of cells the cell that this constraint's component will span in the indicated dimension. <code>1</code> is default and + * means that it only spans the current cell. <code>LayoutUtil.INF</code> is used to indicate a span to the end of the column/row. + * <p> + * Note that only the first component will be checked for this property. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @param cells The number of cells to span (i.e. merge). + */ + public void setSpanX(int cells) + { + this.spanX = cells; + } + + /** Returns the number of cells the cell that this constraint's component will span in the indicated dimension. <code>1</code> is default and + * means that it only spans the current cell. <code>LayoutUtil.INF</code> is used to indicate a span to the end of the column/row. + * <p> + * Note that only the first component will be checked for this property. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @return The current value. + */ + public int getSpanY() + { + return spanY; + } + + /** Sets the number of cells the cell that this constraint's component will span in the indicated dimension. <code>1</code> is default and + * means that it only spans the current cell. <code>LayoutUtil.INF</code> is used to indicate a span to the end of the column/row. + * <p> + * Note that only the first component will be checked for this property. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @param cells The number of cells to span (i.e. merge). + */ + public void setSpanY(int cells) + { + this.spanY = cells; + } + + /** "pushx" indicates that the column that this component is in (this first if the component spans) should default to growing. + * If any other column has been set to grow this push value on the component does nothing as the column's explicit grow weight + * will take precedence. Push is normally used when the grid has not been defined in the layout. + * <p> + * If multiple components in a column has push weights set the largest one will be used for the column. + * @return The current push value. Default is <code>null</code>. + */ + public Float getPushX() + { + return pushX; + } + + /** "pushx" indicates that the column that this component is in (this first if the component spans) should default to growing. + * If any other column has been set to grow this push value on the component does nothing as the column's explicit grow weight + * will take precedence. Push is normally used when the grid has not been defined in the layout. + * <p> + * If multiple components in a column has push weights set the largest one will be used for the column. + * @param weight The new push value. Default is <code>null</code>. + */ + public void setPushX(Float weight) + { + this.pushX = weight; + } + + /** "pushx" indicates that the row that this component is in (this first if the component spans) should default to growing. + * If any other row has been set to grow this push value on the component does nothing as the row's explicit grow weight + * will take precedence. Push is normally used when the grid has not been defined in the layout. + * <p> + * If multiple components in a row has push weights set the largest one will be used for the row. + * @return The current push value. Default is <code>null</code>. + */ + public Float getPushY() + { + return pushY; + } + + /** "pushx" indicates that the row that this component is in (this first if the component spans) should default to growing. + * If any other row has been set to grow this push value on the component does nothing as the row's explicit grow weight + * will take precedence. Push is normally used when the grid has not been defined in the layout. + * <p> + * If multiple components in a row has push weights set the largest one will be used for the row. + * @param weight The new push value. Default is <code>null</code>. + */ + public void setPushY(Float weight) + { + this.pushY = weight; + } + + /** Returns in how many parts the current cell (that this constraint's component will be in) should be split in. If for instance + * it is split in two, the next componet will also share the same cell. Note that the cell can also span a number of + * cells, which means that you can for instance span three cells and split that big cell for two components. Split can be + * set to a very high value to make all components in the same row/column share the same cell (e.g. <code>LayoutUtil.INF</code>). + * <p> + * Note that only the first component will be checked for this property. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @return The current value. + */ + public int getSplit() + { + return split; + } + + /** Sets in how many parts the current cell (that this constraint's component will be in) should be split in. If for instance + * it is split in two, the next componet will also share the same cell. Note that the cell can also span a number of + * cells, which means that you can for instance span three cells and split that big cell for two components. Split can be + * set to a very high value to make all components in the same row/column share the same cell (e.g. <code>LayoutUtil.INF</code>). + * <p> + * Note that only the first component will be checked for this property. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @param parts The number of parts (i.e. component slots) the cell should be divided into. + */ + public void setSplit(int parts) + { + this.split = parts; + } + + /** Tags the component with metadata. Currently only used to tag buttons with for instance "cancel" or "ok" to make them + * show up in the correct order depending on platform. See {@link PlatformDefaults#setButtonOrder(String)} for information. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @return The current value. May be <code>null</code>. + */ + public String getTag() + { + return tag; + } + + /** Optinal tag that gives more context to this constraint's component. It is for instance used to tag buttons in a + * button bar with the button type such as "ok", "help" or "cancel". + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @param tag The new tag. May be <code>null</code>. + */ + public void setTag(String tag) + { + this.tag = tag; + } + + /** Returns if the flow should wrap to the next line/column <b>after</b> the component that this constraint belongs to. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @return The current value. + */ + public boolean isWrap() + { + return wrap != null; + } + + /** Sets if the flow should wrap to the next line/column <b>after</b> the component that this constraint belongs to. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @param b <code>true</code> means wrap after. + */ + public void setWrap(boolean b) + { + wrap = b ? (wrap == null ? DEF_GAP : wrap) : null; + } + + /** Returns the wrap size if it is a custom size. If wrap was set to true with {@link #setWrap(boolean)} then this method will + * return <code>null</code> since that means that the gap size should be the default one as defined in the rows spec. + * @return The custom gap size. NOTE! Will return <code>null</code> for both no wrap <b>and</b> default wrap. + * @see #isWrap() + * @see #setWrap(boolean) + * @since 2.4.2 + */ + public BoundSize getWrapGapSize() + { + return wrap == DEF_GAP ? null : wrap; + } + + /** Set the wrap size and turns wrap on if <code>!= null</code>. + * @param s The custom gap size. NOTE! <code>null</code> will not turn on or off wrap, it will only set the wrap gap size to "default". + * A non-null value will turn on wrap though. + * @see #isWrap() + * @see #setWrap(boolean) + * @since 2.4.2 + */ + public void setWrapGapSize(BoundSize s) + { + wrap = s == null ? (wrap != null ? DEF_GAP : null) : s; + } + + /** Returns if the flow should wrap to the next line/column <b>before</b> the component that this constraint belongs to. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @return The current value. + */ + public boolean isNewline() + { + return newline != null; + } + + /** Sets if the flow should wrap to the next line/column <b>before</b> the component that this constraint belongs to. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @param b <code>true</code> means wrap before. + */ + public void setNewline(boolean b) + { + newline = b ? (newline == null ? DEF_GAP : newline) : null; + } + + /** Returns the newline size if it is a custom size. If newline was set to true with {@link #setNewline(boolean)} then this method will + * return <code>null</code> since that means that the gap size should be the default one as defined in the rows spec. + * @return The custom gap size. NOTE! Will return <code>null</code> for both no newline <b>and</b> default newline. + * @see #isNewline() + * @see #setNewline(boolean) + * @since 2.4.2 + */ + public BoundSize getNewlineGapSize() + { + return newline == DEF_GAP ? null : newline; + } + + /** Set the newline size and turns newline on if <code>!= null</code>. + * @param s The custom gap size. NOTE! <code>null</code> will not turn on or off newline, it will only set the newline gap size to "default". + * A non-null value will turn on newline though. + * @see #isNewline() + * @see #setNewline(boolean) + * @since 2.4.2 + */ + public void setNewlineGapSize(BoundSize s) + { + newline = s == null ? (newline != null ? DEF_GAP : null) : s; + } + + // ************************************************ + // Persistence Delegate and Serializable combined. + // ************************************************ + + private Object readResolve() throws ObjectStreamException + { + return LayoutUtil.getSerializedObject(this); + } + + public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException + { + LayoutUtil.setSerializedObject(this, LayoutUtil.readAsXML(in)); + } + + public void writeExternal(ObjectOutput out) throws IOException + { + if (getClass() == CC.class) + LayoutUtil.writeAsXML(out, this); + } }
\ No newline at end of file diff --git a/prototypes/miglayout/net/miginfocom/layout/ComponentWrapper.java b/prototypes/miglayout/net/miginfocom/layout/ComponentWrapper.java index af96ca6b..d3180c1a 100644 --- a/prototypes/miglayout/net/miginfocom/layout/ComponentWrapper.java +++ b/prototypes/miglayout/net/miginfocom/layout/ComponentWrapper.java @@ -1,258 +1,258 @@ -package net.miginfocom.layout;
-/*
- * License (BSD):
- * ==============
- *
- * Copyright (c) 2004, Mikael Grev, MiG InfoCom AB. (miglayout (at) miginfocom (dot) com)
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification,
- * are permitted provided that the following conditions are met:
- * Redistributions of source code must retain the above copyright notice, this list
- * of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above copyright notice, this
- * list of conditions and the following disclaimer in the documentation and/or other
- * materials provided with the distribution.
- * Neither the name of the MiG InfoCom AB nor the names of its contributors may be
- * used to endorse or promote products derived from this software without specific
- * prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
- * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
- * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
- * OF SUCH DAMAGE.
- *
- * @version 1.0
- * @author Mikael Grev, MiG InfoCom AB
- * Date: 2006-sep-08
- */
-
-/** A class that wraps the important parts of a Component.
- * <p>
- * <b>NOTE!</b>.equals() and .hashcode() should be shunted to the wrapped component. E.g.
- * <pre>
- * public int hashCode()
- {
- return getComponent().hashCode();
- }
-
- public final boolean equals(Object o)
- {
- if (o == null || o instanceof ComponentWrapper == false)
- return false;
-
- return getComponent().equals(((ComponentWrapper) o).getComponent());
- }
- * </pre>
- */
-public interface ComponentWrapper
-{
- static final int TYPE_UNSET = -1;
- public static final int TYPE_UNKNOWN = 0;
- public static final int TYPE_CONTAINER = 1;
- public static final int TYPE_LABEL = 2;
- public static final int TYPE_TEXT_FIELD = 3;
- public static final int TYPE_TEXT_AREA = 4;
- public static final int TYPE_BUTTON = 5;
- public static final int TYPE_LIST = 6;
- public static final int TYPE_TABLE = 7;
- public static final int TYPE_SCROLL_PANE = 8;
- public static final int TYPE_IMAGE = 9;
- public static final int TYPE_PANEL = 10;
- public static final int TYPE_COMBO_BOX = 11;
- public static final int TYPE_SLIDER = 12;
- public static final int TYPE_SPINNER = 13;
- public static final int TYPE_PROGRESS_BAR = 14;
- public static final int TYPE_TREE = 15;
- public static final int TYPE_CHECK_BOX = 16;
- public static final int TYPE_SCROLL_BAR = 17;
- public static final int TYPE_SEPARATOR = 18;
-
- /** Returns the actual object that this wrapper is aggregating. This might be needed for getting
- * information about the object that the wrapper interface does not provide.
- * <p>
- * If this is a container the container should be returned instead.
- * @return The actual object that this wrapper is aggregating. Not <code>null</code>.
- */
- public abstract Object getComponent();
-
- /** Returns the current x coordinate for this component.
- * @return The current x coordinate for this component.
- */
- public abstract int getX();
-
- /** Returns the current y coordinate for this component.
- * @return The current y coordinate for this component.
- */
- public abstract int getY();
-
- /** Returns the current width for this component.
- * @return The current width for this component.
- */
- public abstract int getWidth();
-
- /** Returns the current height for this component.
- * @return The current height for this component.
- */
- public abstract int getHeight();
-
- /** Returns the screen x-coordinate for the upper left coordinate of the component layoutable bounds.
- * @return The screen x-coordinate for the upper left coordinate of the component layoutable bounds.
- */
- public abstract int getScreenLocationX();
-
- /** Returns the screen y-coordinate for the upper left coordinate of the component layoutable bounds.
- * @return The screen y-coordinate for the upper left coordinate of the component layoutable bounds.
- */
- public abstract int getScreenLocationY();
-
- /** Returns the minimum width of the component.
- * @return The minimum width of the component.
- */
- public abstract int getMinimumWidth();
-
- /** Returns the minimum height of the component.
- * @return The minimum height of the component.
- */
- public abstract int getMinimumHeight();
-
- /** Returns the preferred width of the component.
- * @return The preferred width of the component.
- */
- public abstract int getPreferredWidth();
-
- /** Returns the preferred height of the component.
- * @return The preferred height of the component.
- */
- public abstract int getPreferredHeight();
-
- /** Returns the maximum width of the component.
- * @return The maximum width of the component.
- */
- public abstract int getMaximumWidth();
-
- /** Returns the maximum height of the component.
- * @return The maximum height of the component.
- */
- public abstract int getMaximumHeight();
-
- /** Sets the component's bounds.
- * @param x The x coordinate.
- * @param y The y coordinate.
- * @param width The width.
- * @param height The height.
- */
- public abstract void setBounds(int x, int y, int width, int height);
-
- /** Returns if the component's visibility is set to <code>true</code>. This should not return if the component is
- * actually visibile, but if the visibility is set to true or not.
- * @return <code>true</code> means visible.
- */
- public abstract boolean isVisible();
-
- /** Returns the baseline for the component given the suggested height.
- * @param width The width to calculate for if other than the current. If <code>-1</code> the current size should be used.
- * @param height The height to calculate for if other than the current. If <code>-1</code> the current size should be used.
- * @return The baseline from the top or -1 if not applicable.
- */
- public abstract int getBaseline(int width, int height);
-
- /** Returns if the component has a baseline and if it can be retrieved. Should for instance return
- * <code>false</code> for Swing before mustang.
- * @return If the component has a baseline and if it can be retrieved.
- */
- public abstract boolean hasBaseline();
-
- /** Returns the container for this component.
- * @return The container for this component. Should never be <code>null</code>.
- */
- public abstract ContainerWrapper getParent();
-
- /** Returns the pixel unit factor for the horizontal or vertical dimension.
- * <p>
- * The factor is 1 for both dimensions on the normal font in a JPanel on Windows. The factor should increase with a bigger "X".
- * <p>
- * This is the Swing version:
- * <pre>
- * Rectangle2D r = fm.getStringBounds("X", parent.getGraphics());
- * wFactor = r.getWidth() / 6;
- * hFactor = r.getHeight() / 13.27734375f;
- * </pre>
- * @param isHor If it is the horizontal factor that should be returned.
- * @return The factor.
- */
- public abstract float getPixelUnitFactor(boolean isHor);
-
- /** Returns the DPI (Dots Per Inch) of the screen the component is currently in or for the default
- * screen if the component is not visible.
- * @return The DPI.
- */
- public abstract int getHorizontalScreenDPI();
-
- /** Returns the DPI (Dots Per Inch) of the screen the component is currently in or for the default
- * screen if the component is not visible.
- * @return The DPI.
- */
- public abstract int getVerticalScreenDPI();
-
- /** Returns the pixel size of the screen that the component is currently in or for the default
- * screen if the component is not visible or <code>null</code>.
- * @return The screen size. E.g. <code>1280</code>.
- */
- public abstract int getScreenWidth();
-
- /** Returns the pixel size of the screen that the component is currently in or for the default
- * screen if the component is not visible or <code>null</code>.
- * @return The screen size. E.g. <code>1024</code>.
- */
- public abstract int getScreenHeight();
-
- /** Returns a String id that can be used to reference the component in link constraints. This value should
- * return the default id for the component. The id can be set for a component in the constraints and if
- * so the value returned by this method will never be used. If there are no sensible id for the component
- * <code>null</code> should be returned.
- * <p>
- * For instance the Swing implementation returns the string returned from <code>Component.getName()</code>.
- * @return The string link id or <code>null</code>.
- */
- public abstract String getLinkId();
-
- /** Returns a hash code that should be resonably different for anything that might change the layout. This value is used to
- * know if the component layout needs to clear any caches.
- * @return A hash code that should be resonably different for anything that might change the layout. Returns -1 if the widget is
- * disposed.
- */
- public abstract int getLayoutHashCode();
-
- /** Returns the padding on a component by component basis. This method can be overridden to return padding to compensate for example for
- * borders that have shadows or where the outer most pixel is not the visual "edge" to align to.
- * <p>
- * Default implementation returnes <code>null</code> for all components except for Windows XP's JTabbedPane which will return new Insets(0, 0, 2, 2).
- * <p>
- * <b>NOTE!</B> To reduce cenerated garbage the returned padding should never be changed so that the same insets can be returned many times.
- * @return <code>null</code> if no padding. <b>NOTE!</B> To reduce cenerated garbage the returned padding should never be changed so that
- * the same insets can be returned many times. [top, left, bottom, right]
- */
- public int[] getVisualPadding();
-
- /** Paints component outline to indicate where it is.
- */
- public abstract void paintDebugOutline();
-
- /** Returns the type of component that this wrapper is wrapping.
- * <p>
- * This method can be invoked often so the result should be cached.
- * @param disregardScrollPane Is <code>true</code> any wrapping scroll pane should be disregarded and the type
- * of the scrolled component should be returned.
- * @return The type of component that this wrapper is wrapping. E.g. {@link #TYPE_LABEL}.
- */
- public abstract int getComponetType(boolean disregardScrollPane);
-
- ;
+package net.miginfocom.layout; +/* + * License (BSD): + * ============== + * + * Copyright (c) 2004, Mikael Grev, MiG InfoCom AB. (miglayout (at) miginfocom (dot) com) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright notice, this list + * of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * Neither the name of the MiG InfoCom AB nor the names of its contributors may be + * used to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * @version 1.0 + * @author Mikael Grev, MiG InfoCom AB + * Date: 2006-sep-08 + */ + +/** A class that wraps the important parts of a Component. + * <p> + * <b>NOTE!</b>.equals() and .hashcode() should be shunted to the wrapped component. E.g. + * <pre> + * public int hashCode() + { + return getComponent().hashCode(); + } + + public final boolean equals(Object o) + { + if (o == null || o instanceof ComponentWrapper == false) + return false; + + return getComponent().equals(((ComponentWrapper) o).getComponent()); + } + * </pre> + */ +public interface ComponentWrapper +{ + static final int TYPE_UNSET = -1; + public static final int TYPE_UNKNOWN = 0; + public static final int TYPE_CONTAINER = 1; + public static final int TYPE_LABEL = 2; + public static final int TYPE_TEXT_FIELD = 3; + public static final int TYPE_TEXT_AREA = 4; + public static final int TYPE_BUTTON = 5; + public static final int TYPE_LIST = 6; + public static final int TYPE_TABLE = 7; + public static final int TYPE_SCROLL_PANE = 8; + public static final int TYPE_IMAGE = 9; + public static final int TYPE_PANEL = 10; + public static final int TYPE_COMBO_BOX = 11; + public static final int TYPE_SLIDER = 12; + public static final int TYPE_SPINNER = 13; + public static final int TYPE_PROGRESS_BAR = 14; + public static final int TYPE_TREE = 15; + public static final int TYPE_CHECK_BOX = 16; + public static final int TYPE_SCROLL_BAR = 17; + public static final int TYPE_SEPARATOR = 18; + + /** Returns the actual object that this wrapper is aggregating. This might be needed for getting + * information about the object that the wrapper interface does not provide. + * <p> + * If this is a container the container should be returned instead. + * @return The actual object that this wrapper is aggregating. Not <code>null</code>. + */ + public abstract Object getComponent(); + + /** Returns the current x coordinate for this component. + * @return The current x coordinate for this component. + */ + public abstract int getX(); + + /** Returns the current y coordinate for this component. + * @return The current y coordinate for this component. + */ + public abstract int getY(); + + /** Returns the current width for this component. + * @return The current width for this component. + */ + public abstract int getWidth(); + + /** Returns the current height for this component. + * @return The current height for this component. + */ + public abstract int getHeight(); + + /** Returns the screen x-coordinate for the upper left coordinate of the component layoutable bounds. + * @return The screen x-coordinate for the upper left coordinate of the component layoutable bounds. + */ + public abstract int getScreenLocationX(); + + /** Returns the screen y-coordinate for the upper left coordinate of the component layoutable bounds. + * @return The screen y-coordinate for the upper left coordinate of the component layoutable bounds. + */ + public abstract int getScreenLocationY(); + + /** Returns the minimum width of the component. + * @return The minimum width of the component. + */ + public abstract int getMinimumWidth(); + + /** Returns the minimum height of the component. + * @return The minimum height of the component. + */ + public abstract int getMinimumHeight(); + + /** Returns the preferred width of the component. + * @return The preferred width of the component. + */ + public abstract int getPreferredWidth(); + + /** Returns the preferred height of the component. + * @return The preferred height of the component. + */ + public abstract int getPreferredHeight(); + + /** Returns the maximum width of the component. + * @return The maximum width of the component. + */ + public abstract int getMaximumWidth(); + + /** Returns the maximum height of the component. + * @return The maximum height of the component. + */ + public abstract int getMaximumHeight(); + + /** Sets the component's bounds. + * @param x The x coordinate. + * @param y The y coordinate. + * @param width The width. + * @param height The height. + */ + public abstract void setBounds(int x, int y, int width, int height); + + /** Returns if the component's visibility is set to <code>true</code>. This should not return if the component is + * actually visibile, but if the visibility is set to true or not. + * @return <code>true</code> means visible. + */ + public abstract boolean isVisible(); + + /** Returns the baseline for the component given the suggested height. + * @param width The width to calculate for if other than the current. If <code>-1</code> the current size should be used. + * @param height The height to calculate for if other than the current. If <code>-1</code> the current size should be used. + * @return The baseline from the top or -1 if not applicable. + */ + public abstract int getBaseline(int width, int height); + + /** Returns if the component has a baseline and if it can be retrieved. Should for instance return + * <code>false</code> for Swing before mustang. + * @return If the component has a baseline and if it can be retrieved. + */ + public abstract boolean hasBaseline(); + + /** Returns the container for this component. + * @return The container for this component. Should never be <code>null</code>. + */ + public abstract ContainerWrapper getParent(); + + /** Returns the pixel unit factor for the horizontal or vertical dimension. + * <p> + * The factor is 1 for both dimensions on the normal font in a JPanel on Windows. The factor should increase with a bigger "X". + * <p> + * This is the Swing version: + * <pre> + * Rectangle2D r = fm.getStringBounds("X", parent.getGraphics()); + * wFactor = r.getWidth() / 6; + * hFactor = r.getHeight() / 13.27734375f; + * </pre> + * @param isHor If it is the horizontal factor that should be returned. + * @return The factor. + */ + public abstract float getPixelUnitFactor(boolean isHor); + + /** Returns the DPI (Dots Per Inch) of the screen the component is currently in or for the default + * screen if the component is not visible. + * @return The DPI. + */ + public abstract int getHorizontalScreenDPI(); + + /** Returns the DPI (Dots Per Inch) of the screen the component is currently in or for the default + * screen if the component is not visible. + * @return The DPI. + */ + public abstract int getVerticalScreenDPI(); + + /** Returns the pixel size of the screen that the component is currently in or for the default + * screen if the component is not visible or <code>null</code>. + * @return The screen size. E.g. <code>1280</code>. + */ + public abstract int getScreenWidth(); + + /** Returns the pixel size of the screen that the component is currently in or for the default + * screen if the component is not visible or <code>null</code>. + * @return The screen size. E.g. <code>1024</code>. + */ + public abstract int getScreenHeight(); + + /** Returns a String id that can be used to reference the component in link constraints. This value should + * return the default id for the component. The id can be set for a component in the constraints and if + * so the value returned by this method will never be used. If there are no sensible id for the component + * <code>null</code> should be returned. + * <p> + * For instance the Swing implementation returns the string returned from <code>Component.getName()</code>. + * @return The string link id or <code>null</code>. + */ + public abstract String getLinkId(); + + /** Returns a hash code that should be resonably different for anything that might change the layout. This value is used to + * know if the component layout needs to clear any caches. + * @return A hash code that should be resonably different for anything that might change the layout. Returns -1 if the widget is + * disposed. + */ + public abstract int getLayoutHashCode(); + + /** Returns the padding on a component by component basis. This method can be overridden to return padding to compensate for example for + * borders that have shadows or where the outer most pixel is not the visual "edge" to align to. + * <p> + * Default implementation returnes <code>null</code> for all components except for Windows XP's JTabbedPane which will return new Insets(0, 0, 2, 2). + * <p> + * <b>NOTE!</B> To reduce cenerated garbage the returned padding should never be changed so that the same insets can be returned many times. + * @return <code>null</code> if no padding. <b>NOTE!</B> To reduce cenerated garbage the returned padding should never be changed so that + * the same insets can be returned many times. [top, left, bottom, right] + */ + public int[] getVisualPadding(); + + /** Paints component outline to indicate where it is. + */ + public abstract void paintDebugOutline(); + + /** Returns the type of component that this wrapper is wrapping. + * <p> + * This method can be invoked often so the result should be cached. + * @param disregardScrollPane Is <code>true</code> any wrapping scroll pane should be disregarded and the type + * of the scrolled component should be returned. + * @return The type of component that this wrapper is wrapping. E.g. {@link #TYPE_LABEL}. + */ + public abstract int getComponetType(boolean disregardScrollPane); + + ; }
\ No newline at end of file diff --git a/prototypes/miglayout/net/miginfocom/layout/ConstraintParser.java b/prototypes/miglayout/net/miginfocom/layout/ConstraintParser.java index 9abeafa7..7bea17d0 100644 --- a/prototypes/miglayout/net/miginfocom/layout/ConstraintParser.java +++ b/prototypes/miglayout/net/miginfocom/layout/ConstraintParser.java @@ -1,1409 +1,1409 @@ -package net.miginfocom.layout;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.Map;
-/*
- * License (BSD):
- * ==============
- *
- * Copyright (c) 2004, Mikael Grev, MiG InfoCom AB. (miglayout (at) miginfocom (dot) com)
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification,
- * are permitted provided that the following conditions are met:
- * Redistributions of source code must retain the above copyright notice, this list
- * of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above copyright notice, this
- * list of conditions and the following disclaimer in the documentation and/or other
- * materials provided with the distribution.
- * Neither the name of the MiG InfoCom AB nor the names of its contributors may be
- * used to endorse or promote products derived from this software without specific
- * prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
- * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
- * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
- * OF SUCH DAMAGE.
- *
- * @version 1.0
- * @author Mikael Grev, MiG InfoCom AB
- * Date: 2006-sep-08
- */
-
-/** Parses string constraints.
- */
-public final class ConstraintParser
-{
- private ConstraintParser()
- {
- }
-
- /** Parses the layout constraints and stores the parsed values in the transient (cache) member varables.
- * @param s The String to parse. Should not be <code>null</code> and <b>must be lower case and trimmed</b>.
- * @throws RuntimeException if the constaint was not valid.
- * @return The parsed constraint. Never <code>null</code>.
- */
- public static LC parseLayoutConstraint(String s)
- {
- LC lc = new LC();
- if (s.length() == 0)
- return lc;
-
- String[] parts = toTrimmedTokens(s, ',');
-
- // First check for "ltr" or "rtl" since that will affect the interpretation of the other constraints.
- for (int i = 0; i < parts.length; i++) {
- String part = parts[i];
- if (part == null)
- continue;
-
- int len = part.length();
- if (len == 3 || len == 11) { // Optimization
- if (part.equals("ltr") || part.equals("rtl") || part.equals("lefttoright") || part.equals("righttoleft")) {
- lc.setLeftToRight(part.charAt(0) == 'l' ? Boolean.TRUE : Boolean.FALSE);
- parts[i] = null; // So we will not try to interpret it again
- }
-
- if (part.equals("ttb") || part.equals("btt") || part.equals("toptobottom") || part.equals("bottomtotop")) {
- lc.setTopToBottom(part.charAt(0) == 't');
- parts[i] = null; // So we will not try to interpret it again
- }
- }
- }
-
- for (int i = 0; i < parts.length; i++) {
- String part = parts[i];
- if (part == null || part.length() == 0)
- continue;
-
- try {
- int ix = -1;
- char c = part.charAt(0);
-
- if (c == 'w') {
- ix = startsWithLenient(part, "wrap", -1, true);
- if (ix > -1) {
- String num = part.substring(ix).trim();
- lc.setWrapAfter(num.length() != 0 ? Integer.parseInt(num) : 0);
- continue;
- }
- }
-
- if (c == 'g') {
- if (part.startsWith("gapx ")) {
- lc.setGridGapX(parseBoundSize(part.substring(5).trim(), true, true));
- continue;
- }
-
- if (part.startsWith("gapy ")) {
- lc.setGridGapY(parseBoundSize(part.substring(5).trim(), true, false));
- continue;
- }
-
- if (part.startsWith("gap ")) {
- String[] gaps = toTrimmedTokens(part.substring(4).trim(), ' ');
- lc.setGridGapX(parseBoundSize(gaps[0], true, true));
- lc.setGridGapY(gaps.length > 1 ? parseBoundSize(gaps[1], true, false) : lc.getGridGapX());
- continue;
- }
- }
-
- if (c == 'd') {
- ix = startsWithLenient(part, "debug", 5, true);
- if (ix > -1) {
- String millis = part.substring(ix).trim();
- lc.setDebugMillis(millis.length() > 0 ? Integer.parseInt(millis) : 1000);
- continue;
- }
- }
-
- if (c == 'n') {
- if (part.equals("nogrid")) {
- lc.setNoGrid(true);
- continue;
- }
-
- if (part.equals("nocache")) {
- lc.setNoCache(true);
- continue;
- }
-
- if (part.equals("novisualpadding")) {
- lc.setVisualPadding(false);
- continue;
- }
- }
-
- if (c == 'f') {
- if (part.equals("fill") || part.equals("fillx") || part.equals("filly")) {
- lc.setFillX(part.length() == 4 || part.charAt(4) == 'x');
- lc.setFillY(part.length() == 4 || part.charAt(4) == 'y');
- continue;
- }
-
- if (part.equals("flowy")) {
- lc.setFlowX(false);
- continue;
- }
-
- if (part.equals("flowx")) {
- lc.setFlowX(true); // This is the default but added for consistency
- continue;
- }
- }
-
- if (c == 'i') {
- ix = startsWithLenient(part, "insets", 3, true);
- if (ix > -1) {
- String insStr = part.substring(ix).trim();
- UnitValue[] ins = parseInsets(insStr, true);
- LayoutUtil.putCCString(ins, insStr);
- lc.setInsets(ins);
- continue;
- }
- }
-
- if (c == 'a') {
- ix = startsWithLenient(part, new String[] {"aligny", "ay"}, new int[] {6, 2}, true);
- if (ix > -1) {
- lc.setAlignY(parseUnitValueOrAlign(part.substring(ix).trim(), false, null));
- continue;
- }
-
- ix = startsWithLenient(part, new String[] {"alignx", "ax"}, new int[] {6, 2}, true);
- if (ix > -1) {
- lc.setAlignX(parseUnitValueOrAlign(part.substring(ix).trim(), true, null));
- continue;
- }
-
- ix = startsWithLenient(part, "align", 2, true);
- if (ix > -1) {
- String[] gaps = toTrimmedTokens(part.substring(ix).trim(), ' ');
- lc.setAlignX(parseUnitValueOrAlign(gaps[0], true, null));
- lc.setAlignY(gaps.length > 1 ? parseUnitValueOrAlign(gaps[1], false, null) : lc.getAlignX());
- continue;
- }
- }
-
- if (c == 'h' && part.startsWith("hidemode ")) {
- lc.setHideMode(Integer.parseInt(part.substring(9)));
- continue;
- }
-
- if (lc.getAlignX() == null) {
- UnitValue alignX = parseAlignKeywords(part, true);
- if (alignX != null) {
- lc.setAlignX(alignX);
- continue;
- }
- }
-
- UnitValue alignY = parseAlignKeywords(part, false);
- if (alignY != null) {
- lc.setAlignY(alignY);
- continue;
- }
-
- throw new IllegalArgumentException("Unknown Constraint: '" + part + "'\n");
-
- } catch (Exception ex) {
- throw new IllegalArgumentException("Illegal Constraint: '" + part + "'\n" + ex.getMessage());
- }
- }
-
-// lc = (LC) serializeTest(lc);
-
- return lc;
- }
-
- /** Parses the column or rows constraints. They normally looks something like <code>"[min:pref]rel[10px][]"</code>.
- * @param s The string to parse. Not <code>null</code>.
- * @return An array of {@link DimConstraint}s that is as manu are there exist "[...]" sections in the string that is parsed.
- * @throws RuntimeException if the constaint was not valid.
- */
- public static AC parseRowConstraints(String s)
- {
- return parseAxisConstraint(s, false);
- }
-
- /** Parses the column or rows constraints. They normally looks something like <code>"[min:pref]rel[10px][]"</code>.
- * @param s The string to parse. Not <code>null</code>.
- * @return An array of {@link DimConstraint}s that is as manu are there exist "[...]" sections in the string that is parsed.
- * @throws RuntimeException if the constaint was not valid.
- */
- public static AC parseColumnConstraints(String s)
- {
- return parseAxisConstraint(s, true);
- }
-
- /** Parses the column or rows constraints. They normally looks something like <code>"[min:pref]rel[10px][]"</code>.
- * @param s The string to parse. Not <code>null</code>.
- * @param isCols If this for columns rather than rows.
- * @return An array of {@link DimConstraint}s that is as manu are there exist "[...]" sections in the string that is parsed.
- * @throws RuntimeException if the constaint was not valid.
- */
- private static AC parseAxisConstraint(String s, boolean isCols)
- {
- s = s.trim();
-
- if (s.length() == 0)
- return new AC(); // Short circuit for performance.
-
- s = s.toLowerCase();
-
- ArrayList<String> parts = getRowColAndGapsTrimmed(s);
-
- BoundSize[] gaps = new BoundSize[(parts.size() >> 1) + 1];
- for (int i = 0, iSz = parts.size(), gIx = 0; i < iSz; i += 2, gIx++)
- gaps[gIx] = parseBoundSize(parts.get(i), true, isCols);
-
- DimConstraint[] colSpecs = new DimConstraint[parts.size() >> 1];
- for (int i = 0, gIx = 0; i < colSpecs.length; i++, gIx++) {
- if (gIx >= gaps.length - 1)
- gIx = gaps.length - 2;
-
- colSpecs[i] = parseDimConstraint(parts.get((i << 1) + 1), gaps[gIx], gaps[gIx + 1], isCols);
- }
-
- AC ac = new AC();
- ac.setConstaints(colSpecs);
-
-// ac = (AC) serializeTest(ac);
-
- return ac;
- }
-
- /** Parses a single column or row constriant.
- * @param s The single constrint to parse. May look something like <code>"min:pref,fill,grow"</code>. Should not be <code>null</code> and <b>must
- * be lower case and trimmed</b>.
- * @param gapBefore The default gap "before" the column/row constraint. Can be overridden with a <code>"gap"</code> section within <code>s</code>.
- * @param gapAfter The default gap "after" the column/row constraint. Can be overridden with a <code>"gap"</code> section within <code>s</code>.
- * @param isCols If the constraints are column constraints rather than row constraints.
- * @return A single constraint. Never <code>null</code>.
- * @throws RuntimeException if the constaint was not valid.
- */
- private static DimConstraint parseDimConstraint(String s, BoundSize gapBefore, BoundSize gapAfter, boolean isCols)
- {
- DimConstraint dimConstraint = new DimConstraint();
-
- // Default values.
- dimConstraint.setGapBefore(gapBefore);
- dimConstraint.setGapAfter(gapAfter);
-
- String[] parts = toTrimmedTokens(s, ',');
- for (int i = 0; i < parts.length; i++) {
- String part = parts[i];
- try {
- if (part.length() == 0)
- continue;
-
- if (part.equals("fill")) {
- dimConstraint.setFill(true);
- dimConstraint.setAlign(null); // Can not have both fill and alignment
- continue;
- }
-
- if (part.equals("nogrid")) {
- dimConstraint.setNoGrid(true);
- continue;
- }
-
- int ix = -1;
- char c = part.charAt(0);
-
- if (c == 's') {
- ix = startsWithLenient(part, new String[] {"sizegroup", "sg"}, new int[] {5, 2}, true);
- if (ix > -1) {
- dimConstraint.setSizeGroup(part.substring(ix).trim());
- continue;
- }
-
-
- ix = startsWithLenient(part, new String[] {"shrinkprio", "shp"}, new int[] {10, 3}, true);
- if (ix > -1) {
- dimConstraint.setShrinkPriority(Integer.parseInt(part.substring(ix).trim()));
- continue;
- }
-
- ix = startsWithLenient(part, "shrink", 6, true);
- if (ix > -1) {
- dimConstraint.setShrink(parseFloat(part.substring(ix).trim(), ResizeConstraint.WEIGHT_100));
- continue;
- }
- }
-
- if (c == 'g') {
- ix = startsWithLenient(part, new String[] {"growpriority", "gp"}, new int[] {5, 2}, true);
- if (ix > -1) {
- dimConstraint.setGrowPriority(Integer.parseInt(part.substring(ix).trim()));
- continue;
- }
-
- ix = startsWithLenient(part, "grow", 4, true);
- if (ix > -1) {
- dimConstraint.setGrow(parseFloat(part.substring(ix).trim(), ResizeConstraint.WEIGHT_100));
- continue;
- }
- }
-
- if (c == 'a') {
- ix = startsWithLenient(part, "align", 2, true);
- if (ix > -1) {
- if (dimConstraint.isFill() == false) // Swallow, but ignore if fill is set.
- dimConstraint.setAlign(parseUnitValueOrAlign(part.substring(ix).trim(), isCols, null));
- continue;
- }
- }
-
- UnitValue align = parseAlignKeywords(part, isCols);
- if (align != null) {
- if (dimConstraint.isFill() == false) // Swallow, but ignore if fill is set.
- dimConstraint.setAlign(align);
- continue;
- }
-
- // Only min:pref:max still left that is ok
- dimConstraint.setSize(parseBoundSize(part, false, isCols));
-
- } catch (Exception ex) {
- throw new IllegalArgumentException("Illegal contraint: '" + part + "'\n" + ex.getMessage());
- }
- }
- return dimConstraint;
- }
-
- /** Parses all component constraints and stores the parsed values in the transient (cache) member varables.
- * @param constrMap The constraints as <code>String</code>s. Strings <b>must be lower case and trimmed</b>
- * @return The parsed constraints. Never <code>null</code>.
- */
- public static Map<ComponentWrapper, CC> parseComponentConstraints(Map<ComponentWrapper, String> constrMap)
- {
- HashMap<ComponentWrapper, CC> flowConstrMap = new HashMap<ComponentWrapper, CC>();
-
- for (Iterator<Map.Entry<ComponentWrapper, String>> it = constrMap.entrySet().iterator(); it.hasNext();) {
- Map.Entry<ComponentWrapper, String> entry = it.next();
- flowConstrMap.put(entry.getKey(), parseComponentConstraint(entry.getValue()));
- }
-
- return flowConstrMap;
- }
-
- /** Parses one component constraint and returns the parsed value.
- * @param s The string to parse. Should not be <code>null</code> and <b>must be lower case and trimmed</b>.
- * @throws RuntimeException if the constaint was not valid.
- * @return The parsed constraint. Never <code>null</code>.
- */
- public static CC parseComponentConstraint(String s)
- {
- CC cc = new CC();
-
- if (s.length() == 0)
- return cc;
-
- String[] parts = toTrimmedTokens(s, ',');
-
- for (int i = 0; i < parts.length; i++) {
- String part = parts[i];
- try {
- if (part.length() == 0)
- continue;
-
- int ix = -1;
- char c = part.charAt(0);
-
- if (c == 'n') {
- if (part.equals("north")) {
- cc.setDockSide(0);
- continue;
- }
-
- if (part.equals("newline")) {
- cc.setNewline(true);
- continue;
- }
-
- if (part.startsWith("newline ")) {
- String gapSz = part.substring(7).trim();
- cc.setNewlineGapSize(parseBoundSize(gapSz, true, true));
- continue;
- }
- }
-
- if (c == 'f' && (part.equals("flowy") || part.equals("flowx"))) {
- cc.setFlowX(part.charAt(4) == 'x' ? Boolean.TRUE : Boolean.FALSE);
- continue;
- }
-
- if (c == 's') {
- ix = startsWithLenient(part, "skip", 4, true);
- if (ix > -1) {
- String num = part.substring(ix).trim();
- cc.setSkip(num.length() != 0 ? Integer.parseInt(num) : 1);
- continue;
- }
-
- ix = startsWithLenient(part, "split", 5, true);
- if (ix > -1) {
- String split = part.substring(ix).trim();
- cc.setSplit(split.length() > 0 ? Integer.parseInt(split) : LayoutUtil.INF);
- continue;
- }
-
- if (part.equals("south")) {
- cc.setDockSide(2);
- continue;
- }
-
- ix = startsWithLenient(part, new String[] {"spany","sy"}, new int[] {5, 2}, true);
- if (ix > -1) {
- cc.setSpanY(parseSpan(part.substring(ix).trim()));
- continue;
- }
-
- ix = startsWithLenient(part, new String[] {"spanx","sx"}, new int[] {5, 2}, true);
- if (ix > -1) {
- cc.setSpanX(parseSpan(part.substring(ix).trim()));
- continue;
- }
-
- ix = startsWithLenient(part, "span", 4, true);
- if (ix > -1) {
- String[] spans = toTrimmedTokens(part.substring(ix).trim(), ' ');
- cc.setSpanX(spans[0].length() > 0 ? Integer.parseInt(spans[0]) : LayoutUtil.INF);
- cc.setSpanY(spans.length > 1 ? Integer.parseInt(spans[1]) : 1);
- continue;
- }
-
- ix = startsWithLenient(part, "shrinkx", 7, true);
- if (ix > -1) {
- cc.getHorizontal().setShrink(parseFloat(part.substring(ix).trim(), ResizeConstraint.WEIGHT_100));
- continue;
- }
-
- ix = startsWithLenient(part, "shrinky", 7, true);
- if (ix > -1) {
- cc.getVertical().setShrink(parseFloat(part.substring(ix).trim(), ResizeConstraint.WEIGHT_100));
- continue;
- }
-
- ix = startsWithLenient(part, "shrink", 6, false);
- if (ix > -1) {
- String[] shrinks = toTrimmedTokens(part.substring(ix).trim(), ' ');
- cc.getHorizontal().setShrink(parseFloat(part.substring(ix).trim(), ResizeConstraint.WEIGHT_100));
- if (shrinks.length > 1)
- cc.getVertical().setShrink(parseFloat(part.substring(ix).trim(), ResizeConstraint.WEIGHT_100));
- continue;
- }
-
- ix = startsWithLenient(part, new String[] {"shrinkprio", "shp"}, new int[] {10, 3}, true);
- if (ix > -1) {
- String sp = part.substring(ix).trim();
- if (sp.startsWith("x") || sp.startsWith("y")) { // To gandle "gpx", "gpy", "shrinkpriorityx", shrinkpriorityy"
- (sp.startsWith("x") ? cc.getHorizontal() : cc.getVertical()).setShrinkPriority(Integer.parseInt(sp.substring(2)));
- } else {
- String[] shrinks = toTrimmedTokens(sp, ' ');
- cc.getHorizontal().setShrinkPriority(Integer.parseInt(shrinks[0]));
- if (shrinks.length > 1)
- cc.getVertical().setShrinkPriority(Integer.parseInt(shrinks[1]));
- }
- continue;
- }
-
- ix = startsWithLenient(part, new String[] {"sizegroupx", "sizegroupy", "sgx", "sgy"}, new int[] {9, 9, 2, 2}, true);
- if (ix > -1) {
- String sg = part.substring(ix).trim();
- char lc = part.charAt(ix - 1);
- if (lc != 'y')
- cc.getHorizontal().setSizeGroup(sg);
- if (lc != 'x')
- cc.getVertical().setSizeGroup(sg);
- continue;
- }
- }
-
- if (c == 'g') {
- ix = startsWithLenient(part, "growx", 5, true);
- if (ix > -1) {
- cc.getHorizontal().setGrow(parseFloat(part.substring(ix).trim(), ResizeConstraint.WEIGHT_100));
- continue;
- }
-
- ix = startsWithLenient(part, "growy", 5, true);
- if (ix > -1) {
- cc.getVertical().setGrow(parseFloat(part.substring(ix).trim(), ResizeConstraint.WEIGHT_100));
- continue;
- }
-
- ix = startsWithLenient(part, "grow", 4, false);
- if (ix > -1) {
- String[] grows = toTrimmedTokens(part.substring(ix).trim(), ' ');
- cc.getHorizontal().setGrow(parseFloat(grows[0], ResizeConstraint.WEIGHT_100));
- cc.getVertical().setGrow(parseFloat(grows.length > 1 ? grows[1] : "", ResizeConstraint.WEIGHT_100));
- continue;
- }
-
- ix = startsWithLenient(part, new String[] {"growprio", "gp"}, new int[] {8, 2}, true);
- if (ix > -1) {
- String gp = part.substring(ix).trim();
- char c0 = gp.length() > 0 ? gp.charAt(0) : ' ';
- if (c0 == 'x' || c0 == 'y') { // To gandle "gpx", "gpy", "growpriorityx", growpriorityy"
- (c0 == 'x' ? cc.getHorizontal() : cc.getVertical()).setGrowPriority(Integer.parseInt(gp.substring(2)));
- } else {
- String[] grows = toTrimmedTokens(gp, ' ');
- cc.getHorizontal().setGrowPriority(Integer.parseInt(grows[0]));
- if (grows.length > 1)
- cc.getVertical().setGrowPriority(Integer.parseInt(grows[1]));
- }
- continue;
- }
-
- if (part.startsWith("gap")) {
- BoundSize[] gaps = parseGaps(part);
- if (gaps[0] != null)
- cc.getVertical().setGapBefore(gaps[0]);
- if (gaps[1] != null)
- cc.getHorizontal().setGapBefore(gaps[1]);
- if (gaps[2] != null)
- cc.getVertical().setGapAfter(gaps[2]);
- if (gaps[3] != null)
- cc.getHorizontal().setGapAfter(gaps[3]);
- continue;
- }
- }
-
- if (c == 'a') {
- ix = startsWithLenient(part, new String[] {"aligny", "ay"}, new int[] {6, 2}, true);
- if (ix > -1) {
- cc.getVertical().setAlign(parseUnitValueOrAlign(part.substring(ix).trim(), false, null));
- continue;
- }
-
- ix = startsWithLenient(part, new String[] {"alignx", "ax"}, new int[] {6, 2}, true);
- if (ix > -1) {
- cc.getHorizontal().setAlign(parseUnitValueOrAlign(part.substring(ix).trim(), true, null));
- continue;
- }
-
- ix = startsWithLenient(part, "align", 2, true);
- if (ix > -1) {
- String[] gaps = toTrimmedTokens(part.substring(ix).trim(), ' ');
- cc.getHorizontal().setAlign(parseUnitValueOrAlign(gaps[0], true, null));
- if (gaps.length > 1)
- cc.getVertical().setAlign(parseUnitValueOrAlign(gaps[1], false, null));
- continue;
- }
- }
-
- if ((c == 'x' || c == 'y') && part.length() > 2) {
- char c2 = part.charAt(1);
- if (c2 == ' ' || (c2 == '2' && part.charAt(2) == ' ')) {
- if (cc.getPos() == null) {
- cc.setPos(new UnitValue[4]);
- } else if (cc.isBoundsInGrid() == false) {
- throw new IllegalArgumentException("Can not combine 'position' with 'x/y/x2/y2' keywords.");
- }
-
- int edge = (c == 'x' ? 0 : 1) + (c2 == '2' ? 2 : 0);
- UnitValue[] pos = cc.getPos();
- pos[edge] = parseUnitValue(part.substring(2).trim(), null, c == 'x');
- cc.setPos(pos);
- cc.setBoundsInGrid(true);
- continue;
- }
- }
-
- if (c == 'c') {
- ix = startsWithLenient(part, "cell", 4, true);
- if (ix > -1) {
- String[] grs = toTrimmedTokens(part.substring(ix).trim(), ' ');
- if (grs.length < 2)
- throw new IllegalArgumentException("At least two integers must follow " + part);
- cc.setCellX(Integer.parseInt(grs[0]));
- cc.setCellY(Integer.parseInt(grs[1]));
- if (grs.length > 2)
- cc.setSpanX(Integer.parseInt(grs[2]));
- if (grs.length > 3)
- cc.setSpanY(Integer.parseInt(grs[3]));
- continue;
- }
- }
-
- if (c == 'p') {
- ix = startsWithLenient(part, "pos", 3, true);
- if (ix > -1) {
- if (cc.getPos() != null && cc.isBoundsInGrid())
- throw new IllegalArgumentException("Can not combine 'pos' with 'x/y/x2/y2' keywords.");
-
- String[] pos = toTrimmedTokens(part.substring(ix).trim(), ' ');
- UnitValue[] bounds = new UnitValue[4];
- for (int j = 0; j < pos.length; j++)
- bounds[j] = parseUnitValue(pos[j], null, j % 2 == 0);
-
- if (bounds[0] == null && bounds[2] == null || bounds[1] == null && bounds[3] == null)
- throw new IllegalArgumentException("Both x and x2 or y and y2 can not be null!");
-
- cc.setPos(bounds);
- cc.setBoundsInGrid(false);
- continue;
- }
-
- ix = startsWithLenient(part, "pad", 3, true);
- if (ix > -1) {
- UnitValue[] p = parseInsets(part.substring(ix).trim(), false);
- cc.setPadding(new UnitValue[] {
- p[0],
- p.length > 1 ? p[1] : null,
- p.length > 2 ? p[2] : null,
- p.length > 3 ? p[3] : null});
- continue;
- }
-
- ix = startsWithLenient(part, "pushx", 5, true);
- if (ix > -1) {
- cc.setPushX(parseFloat(part.substring(ix).trim(), ResizeConstraint.WEIGHT_100));
- continue;
- }
-
- ix = startsWithLenient(part, "pushy", 5, true);
- if (ix > -1) {
- cc.setPushY(parseFloat(part.substring(ix).trim(), ResizeConstraint.WEIGHT_100));
- continue;
- }
-
- ix = startsWithLenient(part, "push", 4, false);
- if (ix > -1) {
- String[] pushs = toTrimmedTokens(part.substring(ix).trim(), ' ');
- cc.setPushX(parseFloat(pushs[0], ResizeConstraint.WEIGHT_100));
- cc.setPushY(parseFloat(pushs.length > 1 ? pushs[1] : "", ResizeConstraint.WEIGHT_100));
- continue;
- }
- }
-
- if (c == 't') {
- ix = startsWithLenient(part, "tag", 3, true);
- if (ix > -1) {
- cc.setTag(part.substring(ix).trim());
- continue;
- }
- }
-
- if (c == 'w' || c == 'h') {
- if (part.equals("wrap")) {
- cc.setWrap(true);
- continue;
- }
-
- if (part.startsWith("wrap ")) {
- String gapSz = part.substring(5).trim();
- cc.setWrapGapSize(parseBoundSize(gapSz, true, true));
- continue;
- }
-
- boolean isHor = c == 'w';
- if (isHor && (part.startsWith("w ") || part.startsWith("width "))) {
- String uvStr = part.substring(part.charAt(1) == ' ' ? 2 : 6).trim();
- BoundSize wbs = parseBoundSize(uvStr, false, true);
- LayoutUtil.putCCString(wbs, uvStr);
- cc.getHorizontal().setSize(wbs);
- continue;
- }
-
- if (!isHor && (part.startsWith("h ") || part.startsWith("height "))) {
- String uvStr = part.substring(part.charAt(1) == ' ' ? 2 : 7).trim();
- BoundSize hbs = parseBoundSize(uvStr, false, false);
- LayoutUtil.putCCString(hbs, uvStr);
- cc.getVertical().setSize(hbs);
- continue;
- }
-
- if (part.startsWith("wmin ") || part.startsWith("wmax ") || part.startsWith("hmin ") || part.startsWith("hmax ")) {
- String uvStr = part.substring(5).trim();
- if (uvStr.length() > 0) {
- UnitValue uv = parseUnitValue(uvStr, null, isHor);
- boolean isMin = part.charAt(3) == 'n';
- DimConstraint dc = isHor ? cc.getHorizontal() : cc.getVertical();
- dc.setSize(new BoundSize(
- isMin ? uv : (dc.getSize() != null ? dc.getSize().getMin() : null),
- dc.getSize() != null ? dc.getSize().getPreferred() : null,
- isMin ? (dc.getSize() != null ? dc.getSize().getMax() : null) : uv,
- uvStr
- ));
- continue;
- }
- }
-
- if (part.equals("west")) {
- cc.setDockSide(1);
-// cc.getVertical().setGrow(ResizeConstraint.WEIGHT_100);
- continue;
- }
-
- if (part.startsWith("hidemode ")) {
- cc.setHideMode(Integer.parseInt(part.substring(9)));
- continue;
- }
- }
-
- if (c == 'i' && part.startsWith("id ")) {
- cc.setId(part.substring(3).trim());
- int dIx = cc.getId().indexOf('.');
- if (dIx == 0 || dIx == cc.getId().length() - 1)
- throw new IllegalArgumentException("Dot must not be first or last!");
-
- continue;
- }
-
- if (c == 'e') {
- if (part.equals("east")) {
- cc.setDockSide(3);
-// cc.getVertical().setGrow(ResizeConstraint.WEIGHT_100);
- continue;
- }
-
- if (part.equals("external")) {
- cc.setExternal(true);
- continue;
- }
-
- ix = startsWithLenient(part, new String[] {"endgroupx", "endgroupy", "egx", "egy"}, new int[] {-1, -1, -1, -1}, true);
- if (ix > -1) {
- String sg = part.substring(ix).trim();
- char lc = part.charAt(ix - 1);
- DimConstraint dc = (lc == 'x' ? cc.getHorizontal() : cc.getVertical());
- dc.setEndGroup(sg);
- continue;
- }
- }
-
- if (c == 'd') {
- if (part.equals("dock north")) {
- cc.setDockSide(0);
- continue;
- }
- if (part.equals("dock west")) {
- cc.setDockSide(1);
- continue;
- }
- if (part.equals("dock south")) {
- cc.setDockSide(2);
- continue;
- }
- if (part.equals("dock east")) {
- cc.setDockSide(3);
- continue;
- }
-
- if (part.equals("dock center")) {
- cc.getHorizontal().setGrow(new Float(100f));
- cc.getVertical().setGrow(new Float(100f));
- continue;
- }
- }
-
- UnitValue horAlign = parseAlignKeywords(part, true);
- if (horAlign != null) {
- cc.getHorizontal().setAlign(horAlign);
- continue;
- }
-
- UnitValue verAlign = parseAlignKeywords(part, false);
- if (verAlign != null) {
- cc.getVertical().setAlign(verAlign);
- continue;
- }
-
- throw new IllegalArgumentException("Unknown keyword.");
-
- } catch (Exception ex) {
- throw new IllegalArgumentException("Illegal Constraint: '" + part + "'\n" + ex.getMessage());
- }
- }
-
-// cc = (CC) serializeTest(cc);
-
- return cc;
- }
-
- /** Parses insets which consists of 1-4 <code>UnitValue</code>s.
- * @param s The string to parse. E.g. "10 10 10 10" or "20". If less than 4 groups the last will be used for the missing.
- * @param acceptPanel If "panel" and "dialog" should be accepted. They are used to access platform defaults.
- * @return An array of length 4 with the parsed insets.
- * @throws IllegalArgumentException if the parsing could not be done.
- */
- public static UnitValue[] parseInsets(String s, boolean acceptPanel)
- {
- if (s.length() == 0 || s.equals("dialog") || s.equals("panel")) {
- if (acceptPanel == false)
- throw new IllegalAccessError("Insets now allowed: " + s + "\n");
-
- boolean isPanel = s.startsWith("p");
- UnitValue[] ins = new UnitValue[4];
- for (int j = 0; j < 4; j++)
- ins[j] = isPanel ? PlatformDefaults.getPanelInsets(j) : PlatformDefaults.getDialogInsets(j);
-
- return ins;
- } else {
- String[] insS = toTrimmedTokens(s, ' ');
- UnitValue[] ins = new UnitValue[4];
- for (int j = 0; j < 4; j++) {
- UnitValue insSz = parseUnitValue(insS[j < insS.length ? j : insS.length - 1], UnitValue.ZERO, j % 2 == 1);
- ins[j] = insSz != null ? insSz : PlatformDefaults.getPanelInsets(j);
- }
- return ins;
- }
- }
-
- /** Parses gaps.
- * @param s The string that contains gap information. Should start with "gap".
- * @return The gaps as specified in <code>s</code>. Indexed: <code>[top,left,bottom,right][min,pref,max]</code> or
- * [before,after][min,pref,max] if <code>oneDim</code> is true.
- */
- private static BoundSize[] parseGaps(String s)
- {
- BoundSize[] ret = new BoundSize[4];
-
- int ix = startsWithLenient(s, "gaptop", -1, true);
- if (ix > -1) {
- s = s.substring(ix).trim();
- ret[0] = parseBoundSize(s, true, false);
- return ret;
- }
-
- ix = startsWithLenient(s, "gapleft", -1, true);
- if (ix > -1) {
- s = s.substring(ix).trim();
- ret[1] = parseBoundSize(s, true, true);
- return ret;
- }
-
- ix = startsWithLenient(s, "gapbottom", -1, true);
- if (ix > -1) {
- s = s.substring(ix).trim();
- ret[2] = parseBoundSize(s, true, false);
- return ret;
- }
-
- ix = startsWithLenient(s, "gapright", -1, true);
- if (ix > -1) {
- s = s.substring(ix).trim();
- ret[3] = parseBoundSize(s, true, true);
- return ret;
- }
-
- ix = startsWithLenient(s, "gapbefore", -1, true);
- if (ix > -1) {
- s = s.substring(ix).trim();
- ret[1] = parseBoundSize(s, true, true);
- return ret;
- }
-
- ix = startsWithLenient(s, "gapafter", -1, true);
- if (ix > -1) {
- s = s.substring(ix).trim();
- ret[3] = parseBoundSize(s, true, true);
- return ret;
- }
-
- ix = startsWithLenient(s, new String[] {"gapx", "gapy"}, null, true);
- if (ix > -1) {
- boolean x = s.charAt(3) == 'x';
- String[] gaps = toTrimmedTokens(s.substring(ix).trim(), ' ');
- ret[x ? 1 : 0] = parseBoundSize(gaps[0], true, x);
- if (gaps.length > 1)
- ret[x ? 3 : 2] = parseBoundSize(gaps[1], true, !x);
- return ret;
- }
-
- ix = startsWithLenient(s, "gap ", 1, true);
- if (ix > -1) {
- String[] gaps = toTrimmedTokens(s.substring(ix).trim(), ' ');
-
- ret[1] = parseBoundSize(gaps[0], true, true); // left
- if (gaps.length > 1) {
- ret[3] = parseBoundSize(gaps[1], true, false); // right
- if (gaps.length > 2) {
- ret[0] = parseBoundSize(gaps[2], true, true); // top
- if (gaps.length > 3)
- ret[2] = parseBoundSize(gaps[3], true, false); // bottom
- }
- }
- return ret;
- }
-
- throw new IllegalArgumentException("Unknown Gap part: '" + s + "'");
- }
-
- private static int parseSpan(String s)
- {
- return s.length() > 0 ? Integer.parseInt(s) : LayoutUtil.INF;
- }
-
- private static Float parseFloat(String s, Float nullVal)
- {
- return s.length() > 0 ? new Float(Float.parseFloat(s)) : nullVal;
- }
-
- /** Parses a singele "min:pref:max" value. May look something like <code>"10px:20lp:30%"</code> or <code>"pref!"</code>.
- * @param s The string to parse. Not <code>null</code>.
- * @param isGap If this bound size is a gap (different empty string handling).
- * @param isHor If the size is for the horizontal dimension.
- * @return A bound size that may be <code>null</code> if the string was "null", "n" or <code>null</code>.
- */
- public static BoundSize parseBoundSize(String s, boolean isGap, boolean isHor)
- {
- if (s.length() == 0 || s.equals("null") || s.equals("n"))
- return null;
-
- boolean push = false;
- if (s.endsWith("push")) {
- if (isGap == false)
- throw new IllegalArgumentException("Only gaps can have 'push' in size. Use as separate keyword for components.");
- push = true;
- int l = s.length();
- s = s.substring(0, l - (s.endsWith(":push") ? 5 : 4));
- if (s.length() == 0)
- return new BoundSize(null, null, null, true, s);
- }
-
- String[] sizes = toTrimmedTokens(s, ':');
- String s0 = sizes[0];
-
- if (sizes.length == 1) {
- boolean hasEM = s0.endsWith("!");
- if (hasEM)
- s0 = s0.substring(0, s0.length() - 1);
- UnitValue uv = parseUnitValue(s0, null, isHor);
- return new BoundSize(((isGap || hasEM) ? uv : null), uv, (hasEM ? uv : null), push, s);
-
- } else if (sizes.length == 2) {
- return new BoundSize(parseUnitValue(s0, null, isHor), parseUnitValue(sizes[1], null, isHor), null, push, s);
- } else if (sizes.length == 3) {
- return new BoundSize(parseUnitValue(s0, null, isHor), parseUnitValue(sizes[1], null, isHor), parseUnitValue(sizes[2], null, isHor), push, s);
- } else {
- throw new IllegalArgumentException("Min:Preferred:Max size section must contain 0, 1 or 2 colons. '" + s + "'");
- }
- }
-
- /** Parses a single unit value that may also be an alignment as parsed by {@link #parseAlignKeywords(String, boolean)}.
- * @param s The string to parse. Not <code>null</code>. May look something like <code>"10px"</code> or <code>"5dlu"</code>.
- * @param isHor If the value is for the horizontal dimension.
- * @param emptyReplacement A replacement if <code>s</code> is empty. May be <code>null</code>.
- * @return The parsed unit value. May be <code>null</code>.
- */
- public static UnitValue parseUnitValueOrAlign(String s, boolean isHor, UnitValue emptyReplacement)
- {
- if (s.length() == 0)
- return emptyReplacement;
-
- UnitValue align = parseAlignKeywords(s, isHor);
- if (align != null)
- return align;
-
- return parseUnitValue(s, emptyReplacement, isHor);
- }
-
- /** Parses a single unit value. E.g. "10px" or "5in"
- * @param s The string to parse. Not <code>null</code>. May look something like <code>"10px"</code> or <code>"5dlu"</code>.
- * @param isHor If the value is for the horizontal dimension.
- * @return The parsed unit value. <code>null</code> is empty string,
- */
- public static UnitValue parseUnitValue(String s, boolean isHor)
- {
- return parseUnitValue(s, null, isHor);
- }
-
- /** Parses a single unit value.
- * @param s The string to parse. May be <code>null</code>. May look something like <code>"10px"</code> or <code>"5dlu"</code>.
- * @param emptyReplacement A replacement <code>s</code> is empty or <code>null</code>. May be <code>null</code>.
- * @param isHor If the value is for the horizontal dimension.
- * @return The parsed unit value. May be <code>null</code>.
- */
- private static UnitValue parseUnitValue(String s, UnitValue emptyReplacement, boolean isHor)
- {
- if (s == null || s.length() == 0)
- return emptyReplacement;
-
- String cs = s; // Save creation string.
- char c0 = s.charAt(0);
-
- // Remove start and end parentheses, if there.
- if (c0 == '(' && s.charAt(s.length() - 1) == ')')
- s = s.substring(1, s.length() - 1);
-
- if (c0 == 'n' && (s.equals("null") || s.equals("n")))
- return null;
-
- if (c0 == 'i' && s.equals("inf"))
- return UnitValue.INF;
-
- int oper = getOper(s);
- boolean inline = oper == UnitValue.ADD || oper == UnitValue.SUB || oper == UnitValue.MUL || oper == UnitValue.DIV;
-
- if (oper != UnitValue.STATIC) { // It is a multi-value
-
- String[] uvs;
- if (inline == false) { // If the format is of type "opr(xxx,yyy)" (compared to in-line "10%+15px")
- String sub = s.substring(4, s.length() - 1).trim();
- uvs = toTrimmedTokens(sub, ',');
- if (uvs.length == 1)
- return parseUnitValue(sub, null, isHor);
- } else {
- char delim;
- if (oper == UnitValue.ADD) {
- delim = '+';
- } else if (oper == UnitValue.SUB) {
- delim = '-';
- } else if (oper == UnitValue.MUL) {
- delim = '*';
- } else { // div left
- delim = '/';
- }
- uvs = toTrimmedTokens(s, delim);
- if (uvs.length > 2) { // More than one +-*/.
- String last = uvs[uvs.length - 1];
- String first = s.substring(0, s.length() - last.length() - 1);
- uvs = new String[] {first, last};
- }
- }
-
- if (uvs.length != 2)
- throw new IllegalArgumentException("Malformed UnitValue: '" + s + "'");
-
- UnitValue sub1 = parseUnitValue(uvs[0], null, isHor);
- UnitValue sub2 = parseUnitValue(uvs[1], null, isHor);
-
- if (sub1 == null || sub2 == null)
- throw new IllegalArgumentException("Malformed UnitValue. Must be two sub-values: '" + s + "'");
-
- return new UnitValue(isHor, oper, sub1, sub2, cs);
- } else {
- try {
- String[] numParts = getNumTextParts(s);
- float value = numParts[0].length() > 0 ? Float.parseFloat(numParts[0]) : 1; // e.g. "related" has no number part..
-
- return new UnitValue(value, numParts[1], isHor, oper, cs);
-
- } catch(Exception e) {
- throw new IllegalArgumentException("Malformed UnitValue: '" + s + "'");
- }
- }
- }
-
- /** Parses alignment keywords and returns the approprieate <code>UnitValue</code>.
- * @param s The string to parse. Not <code>null</code>.
- * @param isHor If alignments for horizontal is checked. <code>false</code> means vertical.
- * @return The unit value or <code>null</code> if not recognized (no exception).
- */
- static UnitValue parseAlignKeywords(String s, boolean isHor)
- {
- if (startsWithLenient(s, "center", 1, false) != -1)
- return UnitValue.CENTER;
-
- if (isHor) {
- if (startsWithLenient(s, "left", 1, false) != -1)
- return UnitValue.LEFT;
-
- if (startsWithLenient(s, "right", 1, false) != -1)
- return UnitValue.RIGHT;
-
- if (startsWithLenient(s, "leading", 4, false) != -1)
- return UnitValue.LEADING;
-
- if (startsWithLenient(s, "trailing", 5, false) != -1)
- return UnitValue.TRAILING;
-
- if (startsWithLenient(s, "label", 5, false) != -1)
- return UnitValue.LABEL;
-
- } else {
-
- if (startsWithLenient(s, "baseline", 4, false) != -1)
- return UnitValue.BASELINE_IDENTITY;
-
- if (startsWithLenient(s, "top", 1, false) != -1)
- return UnitValue.TOP;
-
- if (startsWithLenient(s, "bottom", 1, false) != -1)
- return UnitValue.BOTTOM;
- }
-
- return null;
- }
-
- /** Splits a text-number combination such as "hello 10.0" into <code>{"hello", "10.0"}</code>.
- * @param s The string to split. Not <code>null</code>. Needs be be resonably formatted since the method
- * only finds the first 0-9 or . and cuts the string in half there.
- * @return Always length 2 and no <code>null</code> elements. Elements are "" if no part found.
- */
- private static String[] getNumTextParts(String s)
- {
- for (int i = 0, iSz = s.length(); i < iSz; i++) {
- char c = s.charAt(i);
- if (c == ' ')
- throw new IllegalArgumentException("Space in UnitValue: '" + s + "'");
-
- if ((c < '0' || c > '9') && c != '.' && c != '-')
- return new String[] {s.substring(0, i).trim(), s.substring(i).trim()};
- }
- return new String[] {s, ""};
- }
-
- /** Returns the operation depending on the start character.
- * @param s The string to check. Not <code>null</code>.
- * @return E.g. UnitValue.ADD, UnitValue.SUB or UnitValue.STATIC. Returns negative value for in-line operations.
- */
- private static int getOper(String s)
- {
- int len = s.length();
- if (len < 3)
- return UnitValue.STATIC;
-
- if (len > 5 && s.charAt(3) == '(' && s.charAt(len - 1) == ')') {
- if (s.startsWith("min("))
- return UnitValue.MIN;
-
- if (s.startsWith("max("))
- return UnitValue.MAX;
-
- if (s.startsWith("mid("))
- return UnitValue.MID;
- }
-
- // Try in-line add/sub. E.g. "pref+10px".
- for (int j = 0; j < 2; j++) { // First +- then */ (precedence)
- for (int i = len - 1, p = 0; i > 0; i--) {
- char c = s.charAt(i);
- if (c == ')') {
- p++;
- } else if (c == '(') {
- p--;
- } else if (p == 0) {
- if (j == 0) {
- if (c == '+')
- return UnitValue.ADD;
- if (c == '-')
- return UnitValue.SUB;
- } else {
- if (c == '*')
- return UnitValue.MUL;
- if (c == '/')
- return UnitValue.DIV;
- }
- }
- }
- }
- return UnitValue.STATIC;
- }
-
- /** Returns if a string shares at least a specified numbers starting characters with a number of matches.
- * <p>
- * This method just excercises {@link #startsWithLenient(String, String, int, boolean)} with every one of
- * <code>matches</code> and <code>minChars</code>.
- * @param s The string to check. Not <code>null</code>.
- * @param matches A number of possible starts for <code>s</code>.
- * @param minChars The mimimum number of characters to match for every element in <code>matches</code>. Needs
- * to be of same length as <code>matches</code>. Can be <code>null</code>.
- * @param acceptTrailing If after the required number of charecters are matched onrecognized characters that are not
- * in one of the the <code>matches</code> string should be accepted. For instance if "abczz" should be matched with
- * "abcdef" and min chars 3.
- * @return The index of the first unmatched character if <code>minChars</code> was reached or <code>-1</code> if a match was not
- * found.
- */
- private static int startsWithLenient(String s, String[] matches, int[] minChars, boolean acceptTrailing)
- {
- for (int i = 0; i < matches.length; i++) {
- int minChar = minChars != null ? minChars[i] : -1;
- int ix = startsWithLenient(s, matches[i], minChar, acceptTrailing);
- if (ix > -1)
- return ix;
- }
- return -1;
- }
-
- /** Returns if a string shares at least a specified numbers starting characters with a match.
- * @param s The string to check. Not <code>null</code> and must be trimmed.
- * @param match The possible start for <code>s</code>. Not <code>null</code> and must be trimmed.
- * @param minChars The mimimum number of characters to match to <code>s</code> for it this to be considered a match. -1 means
- * the full length of <code>match</code>.
- * @param acceptTrailing If after the required number of charecters are matched unrecognized characters that are not
- * in one of the the <code>matches</code> string should be accepted. For instance if "abczz" should be matched with
- * "abcdef" and min chars 3.
- * @return The index of the first unmatched character if <code>minChars</code> was reached or <code>-1</code> if a match was not
- * found.
- */
- private static int startsWithLenient(String s, String match, int minChars, boolean acceptTrailing)
- {
- if (s.charAt(0) != match.charAt(0)) // Fast sanity check.
- return -1;
-
- if (minChars == -1)
- minChars = match.length();
-
- int sSz = s.length();
- if (sSz < minChars)
- return -1;
-
- int mSz = match.length();
- int sIx = 0;
- for (int mIx = 0; mIx < mSz; sIx++, mIx++) {
- while (sIx < sSz && (s.charAt(sIx) == ' ' || s.charAt(sIx) == '_')) // Disregard spaces and _
- sIx++;
-
- if (sIx >= sSz || s.charAt(sIx) != match.charAt(mIx))
- return mIx >= minChars && (acceptTrailing || sIx >= sSz) && (sIx >= sSz || s.charAt(sIx - 1) == ' ') ? sIx : -1;
- }
-// return (sIx >= sSz || acceptTrailing) && (sIx >= sSz || s.charAt(sIx) == ' ') ? sIx : -1;
- return sIx >= sSz || acceptTrailing ||s.charAt(sIx) == ' ' ? sIx : -1;
- }
-
- /** Parses a string and returns it in those parts of the string that are separated with a <code>sep</code> character.
- * <p>
- * separator characters within parentheses will not be counted or handled in any way, whatever the depth.
- * @param s The string to parse. If it starts and/or ends with a <code>sep</code> the first and/or last element returned will be "". If
- * two <code>sep</code> are next to eachother and empty element will be "between" the periods. The <code>sep</code> themselves will never be returned.
- * @param sep The separator char.
- * @return Those parts of the string that are separated with <code>sep</code>. Never null and at least of size 1
- */
- private final static String[] toTrimmedTokens(String s, char sep)
- {
- int toks = 0, sSize = s.length();
-
- // Count the sep:s
- int p = 0;
- for(int i = 0; i < sSize; i++) {
- char c = s.charAt(i);
- if (c == '(') {
- p++;
- } else if (c == ')') {
- p--;
- } else if (p == 0 && c == sep) {
- toks++;
- }
- if (p < 0)
- throw new IllegalArgumentException("Unbalanced parentheses: '" + s + "'");
- }
- if (p != 0)
- throw new IllegalArgumentException("Unbalanced parentheses: '" + s + "'");
-
- if (toks == 0)
- return new String [] {s.trim()};
-
- String[] retArr = new String[toks + 1];
-
- int st = 0, pNr = 0;
- p = 0;
- for (int i = 0; i < sSize; i++) {
-
- char c = s.charAt(i);
- if (c == '(') {
- p++;
- } else if (c == ')') {
- p--;
- } else if (p == 0 && c == sep) {
- retArr[pNr++] = s.substring(st, i).trim();
- st = i + 1;
- }
- }
-
- retArr[pNr++] = s.substring(st, sSize).trim();
- return retArr;
- }
-
- /** Parses "AAA[BBB]CCC[DDD]EEE" into {"AAA", "BBB", "CCC", "DDD", "EEE", "FFF"}. Handles empty parts. Will always start and end outside
- * a [] block so that the number of returned elemets will always be uneven and at least of length 3.
- * <p>
- * "|" is interprated as "][".
- * @param s The string. Might be "" but not null. Should be trimmed.
- * @return The string divided into elements. Never <code>null</code> and at least of length 3.
- * @throws IllegalArgumentException If a [] mismatch of some kind. (If not same [ as ] count or if the interleave.)
- */
- private final static ArrayList<String> getRowColAndGapsTrimmed(String s)
- {
- if (s.indexOf('|') != -1)
- s = s.replaceAll("\\|", "][");
-
- ArrayList<String> retList = new ArrayList<String>(Math.max(s.length() >> 2 + 1, 3)); // Aprox return length.
- int s0 = 0, s1 = 0; // '[' and ']' count.
- int st = 0; // Start of "next token to add".
- for (int i = 0, iSz = s.length(); i < iSz; i++) {
- char c = s.charAt(i);
- if (c == '[') {
- s0++;
- } else if (c == ']') {
- s1++;
- } else {
- continue;
- }
-
- if (s0 != s1 && (s0 - 1) != s1)
- break; // Wrong [ or ] found. Break for throw.
-
- retList.add(s.substring(st, i).trim());
- st = i + 1;
- }
- if (s0 != s1)
- throw new IllegalArgumentException("'[' and ']' mismatch in row/column format string: " + s);
-
- if (s0 == 0) {
- retList.add("");
- retList.add(s);
- retList.add("");
- } else if (retList.size() % 2 == 0) {
- retList.add(s.substring(st, s.length()));
- }
-
- return retList;
- }
-
- /** Makes <code>null</code> "", trimms and converts to lower case.
- * @param s The string
- * @return Not null.
- */
- public static final String prepare(String s)
- {
- return s != null ? s.trim().toLowerCase() : "";
- }
-
-// /** Tests to serialize and deserialize the object with both XMLEncoder/Decoder and through Serializable
-// * @param o The object to serialize
-// * @return The same object after a tri through the process.
-// */
-// public static final Object serializeTest(Object o)
-// {
-// try {
-// ByteArrayOutputStream barr = new ByteArrayOutputStream();
-// XMLEncoder enc = new XMLEncoder(barr);
-// enc.writeObject(o);
-// enc.close();
-//
-// XMLDecoder dec = new XMLDecoder(new ByteArrayInputStream(barr.toByteArray()));
-// o = dec.readObject();
-// dec.close();
-// } catch (Exception e) {
-// e.printStackTrace();
-// }
-//
-// try {
-// ByteArrayOutputStream barr = new ByteArrayOutputStream();
-// ObjectOutputStream oos = new ObjectOutputStream(barr);
-// oos.writeObject(o);
-// oos.close();
-//
-// ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(barr.toByteArray()));
-// o = ois.readObject();
-// ois.close();
-// } catch (Exception e) {
-// e.printStackTrace();
-// }
-//
-// return o;
-// }
-}
+package net.miginfocom.layout; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +/* + * License (BSD): + * ============== + * + * Copyright (c) 2004, Mikael Grev, MiG InfoCom AB. (miglayout (at) miginfocom (dot) com) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright notice, this list + * of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * Neither the name of the MiG InfoCom AB nor the names of its contributors may be + * used to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * @version 1.0 + * @author Mikael Grev, MiG InfoCom AB + * Date: 2006-sep-08 + */ + +/** Parses string constraints. + */ +public final class ConstraintParser +{ + private ConstraintParser() + { + } + + /** Parses the layout constraints and stores the parsed values in the transient (cache) member varables. + * @param s The String to parse. Should not be <code>null</code> and <b>must be lower case and trimmed</b>. + * @throws RuntimeException if the constaint was not valid. + * @return The parsed constraint. Never <code>null</code>. + */ + public static LC parseLayoutConstraint(String s) + { + LC lc = new LC(); + if (s.length() == 0) + return lc; + + String[] parts = toTrimmedTokens(s, ','); + + // First check for "ltr" or "rtl" since that will affect the interpretation of the other constraints. + for (int i = 0; i < parts.length; i++) { + String part = parts[i]; + if (part == null) + continue; + + int len = part.length(); + if (len == 3 || len == 11) { // Optimization + if (part.equals("ltr") || part.equals("rtl") || part.equals("lefttoright") || part.equals("righttoleft")) { + lc.setLeftToRight(part.charAt(0) == 'l' ? Boolean.TRUE : Boolean.FALSE); + parts[i] = null; // So we will not try to interpret it again + } + + if (part.equals("ttb") || part.equals("btt") || part.equals("toptobottom") || part.equals("bottomtotop")) { + lc.setTopToBottom(part.charAt(0) == 't'); + parts[i] = null; // So we will not try to interpret it again + } + } + } + + for (int i = 0; i < parts.length; i++) { + String part = parts[i]; + if (part == null || part.length() == 0) + continue; + + try { + int ix = -1; + char c = part.charAt(0); + + if (c == 'w') { + ix = startsWithLenient(part, "wrap", -1, true); + if (ix > -1) { + String num = part.substring(ix).trim(); + lc.setWrapAfter(num.length() != 0 ? Integer.parseInt(num) : 0); + continue; + } + } + + if (c == 'g') { + if (part.startsWith("gapx ")) { + lc.setGridGapX(parseBoundSize(part.substring(5).trim(), true, true)); + continue; + } + + if (part.startsWith("gapy ")) { + lc.setGridGapY(parseBoundSize(part.substring(5).trim(), true, false)); + continue; + } + + if (part.startsWith("gap ")) { + String[] gaps = toTrimmedTokens(part.substring(4).trim(), ' '); + lc.setGridGapX(parseBoundSize(gaps[0], true, true)); + lc.setGridGapY(gaps.length > 1 ? parseBoundSize(gaps[1], true, false) : lc.getGridGapX()); + continue; + } + } + + if (c == 'd') { + ix = startsWithLenient(part, "debug", 5, true); + if (ix > -1) { + String millis = part.substring(ix).trim(); + lc.setDebugMillis(millis.length() > 0 ? Integer.parseInt(millis) : 1000); + continue; + } + } + + if (c == 'n') { + if (part.equals("nogrid")) { + lc.setNoGrid(true); + continue; + } + + if (part.equals("nocache")) { + lc.setNoCache(true); + continue; + } + + if (part.equals("novisualpadding")) { + lc.setVisualPadding(false); + continue; + } + } + + if (c == 'f') { + if (part.equals("fill") || part.equals("fillx") || part.equals("filly")) { + lc.setFillX(part.length() == 4 || part.charAt(4) == 'x'); + lc.setFillY(part.length() == 4 || part.charAt(4) == 'y'); + continue; + } + + if (part.equals("flowy")) { + lc.setFlowX(false); + continue; + } + + if (part.equals("flowx")) { + lc.setFlowX(true); // This is the default but added for consistency + continue; + } + } + + if (c == 'i') { + ix = startsWithLenient(part, "insets", 3, true); + if (ix > -1) { + String insStr = part.substring(ix).trim(); + UnitValue[] ins = parseInsets(insStr, true); + LayoutUtil.putCCString(ins, insStr); + lc.setInsets(ins); + continue; + } + } + + if (c == 'a') { + ix = startsWithLenient(part, new String[] {"aligny", "ay"}, new int[] {6, 2}, true); + if (ix > -1) { + lc.setAlignY(parseUnitValueOrAlign(part.substring(ix).trim(), false, null)); + continue; + } + + ix = startsWithLenient(part, new String[] {"alignx", "ax"}, new int[] {6, 2}, true); + if (ix > -1) { + lc.setAlignX(parseUnitValueOrAlign(part.substring(ix).trim(), true, null)); + continue; + } + + ix = startsWithLenient(part, "align", 2, true); + if (ix > -1) { + String[] gaps = toTrimmedTokens(part.substring(ix).trim(), ' '); + lc.setAlignX(parseUnitValueOrAlign(gaps[0], true, null)); + lc.setAlignY(gaps.length > 1 ? parseUnitValueOrAlign(gaps[1], false, null) : lc.getAlignX()); + continue; + } + } + + if (c == 'h' && part.startsWith("hidemode ")) { + lc.setHideMode(Integer.parseInt(part.substring(9))); + continue; + } + + if (lc.getAlignX() == null) { + UnitValue alignX = parseAlignKeywords(part, true); + if (alignX != null) { + lc.setAlignX(alignX); + continue; + } + } + + UnitValue alignY = parseAlignKeywords(part, false); + if (alignY != null) { + lc.setAlignY(alignY); + continue; + } + + throw new IllegalArgumentException("Unknown Constraint: '" + part + "'\n"); + + } catch (Exception ex) { + throw new IllegalArgumentException("Illegal Constraint: '" + part + "'\n" + ex.getMessage()); + } + } + +// lc = (LC) serializeTest(lc); + + return lc; + } + + /** Parses the column or rows constraints. They normally looks something like <code>"[min:pref]rel[10px][]"</code>. + * @param s The string to parse. Not <code>null</code>. + * @return An array of {@link DimConstraint}s that is as manu are there exist "[...]" sections in the string that is parsed. + * @throws RuntimeException if the constaint was not valid. + */ + public static AC parseRowConstraints(String s) + { + return parseAxisConstraint(s, false); + } + + /** Parses the column or rows constraints. They normally looks something like <code>"[min:pref]rel[10px][]"</code>. + * @param s The string to parse. Not <code>null</code>. + * @return An array of {@link DimConstraint}s that is as manu are there exist "[...]" sections in the string that is parsed. + * @throws RuntimeException if the constaint was not valid. + */ + public static AC parseColumnConstraints(String s) + { + return parseAxisConstraint(s, true); + } + + /** Parses the column or rows constraints. They normally looks something like <code>"[min:pref]rel[10px][]"</code>. + * @param s The string to parse. Not <code>null</code>. + * @param isCols If this for columns rather than rows. + * @return An array of {@link DimConstraint}s that is as manu are there exist "[...]" sections in the string that is parsed. + * @throws RuntimeException if the constaint was not valid. + */ + private static AC parseAxisConstraint(String s, boolean isCols) + { + s = s.trim(); + + if (s.length() == 0) + return new AC(); // Short circuit for performance. + + s = s.toLowerCase(); + + ArrayList<String> parts = getRowColAndGapsTrimmed(s); + + BoundSize[] gaps = new BoundSize[(parts.size() >> 1) + 1]; + for (int i = 0, iSz = parts.size(), gIx = 0; i < iSz; i += 2, gIx++) + gaps[gIx] = parseBoundSize(parts.get(i), true, isCols); + + DimConstraint[] colSpecs = new DimConstraint[parts.size() >> 1]; + for (int i = 0, gIx = 0; i < colSpecs.length; i++, gIx++) { + if (gIx >= gaps.length - 1) + gIx = gaps.length - 2; + + colSpecs[i] = parseDimConstraint(parts.get((i << 1) + 1), gaps[gIx], gaps[gIx + 1], isCols); + } + + AC ac = new AC(); + ac.setConstaints(colSpecs); + +// ac = (AC) serializeTest(ac); + + return ac; + } + + /** Parses a single column or row constriant. + * @param s The single constrint to parse. May look something like <code>"min:pref,fill,grow"</code>. Should not be <code>null</code> and <b>must + * be lower case and trimmed</b>. + * @param gapBefore The default gap "before" the column/row constraint. Can be overridden with a <code>"gap"</code> section within <code>s</code>. + * @param gapAfter The default gap "after" the column/row constraint. Can be overridden with a <code>"gap"</code> section within <code>s</code>. + * @param isCols If the constraints are column constraints rather than row constraints. + * @return A single constraint. Never <code>null</code>. + * @throws RuntimeException if the constaint was not valid. + */ + private static DimConstraint parseDimConstraint(String s, BoundSize gapBefore, BoundSize gapAfter, boolean isCols) + { + DimConstraint dimConstraint = new DimConstraint(); + + // Default values. + dimConstraint.setGapBefore(gapBefore); + dimConstraint.setGapAfter(gapAfter); + + String[] parts = toTrimmedTokens(s, ','); + for (int i = 0; i < parts.length; i++) { + String part = parts[i]; + try { + if (part.length() == 0) + continue; + + if (part.equals("fill")) { + dimConstraint.setFill(true); + dimConstraint.setAlign(null); // Can not have both fill and alignment + continue; + } + + if (part.equals("nogrid")) { + dimConstraint.setNoGrid(true); + continue; + } + + int ix = -1; + char c = part.charAt(0); + + if (c == 's') { + ix = startsWithLenient(part, new String[] {"sizegroup", "sg"}, new int[] {5, 2}, true); + if (ix > -1) { + dimConstraint.setSizeGroup(part.substring(ix).trim()); + continue; + } + + + ix = startsWithLenient(part, new String[] {"shrinkprio", "shp"}, new int[] {10, 3}, true); + if (ix > -1) { + dimConstraint.setShrinkPriority(Integer.parseInt(part.substring(ix).trim())); + continue; + } + + ix = startsWithLenient(part, "shrink", 6, true); + if (ix > -1) { + dimConstraint.setShrink(parseFloat(part.substring(ix).trim(), ResizeConstraint.WEIGHT_100)); + continue; + } + } + + if (c == 'g') { + ix = startsWithLenient(part, new String[] {"growpriority", "gp"}, new int[] {5, 2}, true); + if (ix > -1) { + dimConstraint.setGrowPriority(Integer.parseInt(part.substring(ix).trim())); + continue; + } + + ix = startsWithLenient(part, "grow", 4, true); + if (ix > -1) { + dimConstraint.setGrow(parseFloat(part.substring(ix).trim(), ResizeConstraint.WEIGHT_100)); + continue; + } + } + + if (c == 'a') { + ix = startsWithLenient(part, "align", 2, true); + if (ix > -1) { + if (dimConstraint.isFill() == false) // Swallow, but ignore if fill is set. + dimConstraint.setAlign(parseUnitValueOrAlign(part.substring(ix).trim(), isCols, null)); + continue; + } + } + + UnitValue align = parseAlignKeywords(part, isCols); + if (align != null) { + if (dimConstraint.isFill() == false) // Swallow, but ignore if fill is set. + dimConstraint.setAlign(align); + continue; + } + + // Only min:pref:max still left that is ok + dimConstraint.setSize(parseBoundSize(part, false, isCols)); + + } catch (Exception ex) { + throw new IllegalArgumentException("Illegal contraint: '" + part + "'\n" + ex.getMessage()); + } + } + return dimConstraint; + } + + /** Parses all component constraints and stores the parsed values in the transient (cache) member varables. + * @param constrMap The constraints as <code>String</code>s. Strings <b>must be lower case and trimmed</b> + * @return The parsed constraints. Never <code>null</code>. + */ + public static Map<ComponentWrapper, CC> parseComponentConstraints(Map<ComponentWrapper, String> constrMap) + { + HashMap<ComponentWrapper, CC> flowConstrMap = new HashMap<ComponentWrapper, CC>(); + + for (Iterator<Map.Entry<ComponentWrapper, String>> it = constrMap.entrySet().iterator(); it.hasNext();) { + Map.Entry<ComponentWrapper, String> entry = it.next(); + flowConstrMap.put(entry.getKey(), parseComponentConstraint(entry.getValue())); + } + + return flowConstrMap; + } + + /** Parses one component constraint and returns the parsed value. + * @param s The string to parse. Should not be <code>null</code> and <b>must be lower case and trimmed</b>. + * @throws RuntimeException if the constaint was not valid. + * @return The parsed constraint. Never <code>null</code>. + */ + public static CC parseComponentConstraint(String s) + { + CC cc = new CC(); + + if (s.length() == 0) + return cc; + + String[] parts = toTrimmedTokens(s, ','); + + for (int i = 0; i < parts.length; i++) { + String part = parts[i]; + try { + if (part.length() == 0) + continue; + + int ix = -1; + char c = part.charAt(0); + + if (c == 'n') { + if (part.equals("north")) { + cc.setDockSide(0); + continue; + } + + if (part.equals("newline")) { + cc.setNewline(true); + continue; + } + + if (part.startsWith("newline ")) { + String gapSz = part.substring(7).trim(); + cc.setNewlineGapSize(parseBoundSize(gapSz, true, true)); + continue; + } + } + + if (c == 'f' && (part.equals("flowy") || part.equals("flowx"))) { + cc.setFlowX(part.charAt(4) == 'x' ? Boolean.TRUE : Boolean.FALSE); + continue; + } + + if (c == 's') { + ix = startsWithLenient(part, "skip", 4, true); + if (ix > -1) { + String num = part.substring(ix).trim(); + cc.setSkip(num.length() != 0 ? Integer.parseInt(num) : 1); + continue; + } + + ix = startsWithLenient(part, "split", 5, true); + if (ix > -1) { + String split = part.substring(ix).trim(); + cc.setSplit(split.length() > 0 ? Integer.parseInt(split) : LayoutUtil.INF); + continue; + } + + if (part.equals("south")) { + cc.setDockSide(2); + continue; + } + + ix = startsWithLenient(part, new String[] {"spany","sy"}, new int[] {5, 2}, true); + if (ix > -1) { + cc.setSpanY(parseSpan(part.substring(ix).trim())); + continue; + } + + ix = startsWithLenient(part, new String[] {"spanx","sx"}, new int[] {5, 2}, true); + if (ix > -1) { + cc.setSpanX(parseSpan(part.substring(ix).trim())); + continue; + } + + ix = startsWithLenient(part, "span", 4, true); + if (ix > -1) { + String[] spans = toTrimmedTokens(part.substring(ix).trim(), ' '); + cc.setSpanX(spans[0].length() > 0 ? Integer.parseInt(spans[0]) : LayoutUtil.INF); + cc.setSpanY(spans.length > 1 ? Integer.parseInt(spans[1]) : 1); + continue; + } + + ix = startsWithLenient(part, "shrinkx", 7, true); + if (ix > -1) { + cc.getHorizontal().setShrink(parseFloat(part.substring(ix).trim(), ResizeConstraint.WEIGHT_100)); + continue; + } + + ix = startsWithLenient(part, "shrinky", 7, true); + if (ix > -1) { + cc.getVertical().setShrink(parseFloat(part.substring(ix).trim(), ResizeConstraint.WEIGHT_100)); + continue; + } + + ix = startsWithLenient(part, "shrink", 6, false); + if (ix > -1) { + String[] shrinks = toTrimmedTokens(part.substring(ix).trim(), ' '); + cc.getHorizontal().setShrink(parseFloat(part.substring(ix).trim(), ResizeConstraint.WEIGHT_100)); + if (shrinks.length > 1) + cc.getVertical().setShrink(parseFloat(part.substring(ix).trim(), ResizeConstraint.WEIGHT_100)); + continue; + } + + ix = startsWithLenient(part, new String[] {"shrinkprio", "shp"}, new int[] {10, 3}, true); + if (ix > -1) { + String sp = part.substring(ix).trim(); + if (sp.startsWith("x") || sp.startsWith("y")) { // To gandle "gpx", "gpy", "shrinkpriorityx", shrinkpriorityy" + (sp.startsWith("x") ? cc.getHorizontal() : cc.getVertical()).setShrinkPriority(Integer.parseInt(sp.substring(2))); + } else { + String[] shrinks = toTrimmedTokens(sp, ' '); + cc.getHorizontal().setShrinkPriority(Integer.parseInt(shrinks[0])); + if (shrinks.length > 1) + cc.getVertical().setShrinkPriority(Integer.parseInt(shrinks[1])); + } + continue; + } + + ix = startsWithLenient(part, new String[] {"sizegroupx", "sizegroupy", "sgx", "sgy"}, new int[] {9, 9, 2, 2}, true); + if (ix > -1) { + String sg = part.substring(ix).trim(); + char lc = part.charAt(ix - 1); + if (lc != 'y') + cc.getHorizontal().setSizeGroup(sg); + if (lc != 'x') + cc.getVertical().setSizeGroup(sg); + continue; + } + } + + if (c == 'g') { + ix = startsWithLenient(part, "growx", 5, true); + if (ix > -1) { + cc.getHorizontal().setGrow(parseFloat(part.substring(ix).trim(), ResizeConstraint.WEIGHT_100)); + continue; + } + + ix = startsWithLenient(part, "growy", 5, true); + if (ix > -1) { + cc.getVertical().setGrow(parseFloat(part.substring(ix).trim(), ResizeConstraint.WEIGHT_100)); + continue; + } + + ix = startsWithLenient(part, "grow", 4, false); + if (ix > -1) { + String[] grows = toTrimmedTokens(part.substring(ix).trim(), ' '); + cc.getHorizontal().setGrow(parseFloat(grows[0], ResizeConstraint.WEIGHT_100)); + cc.getVertical().setGrow(parseFloat(grows.length > 1 ? grows[1] : "", ResizeConstraint.WEIGHT_100)); + continue; + } + + ix = startsWithLenient(part, new String[] {"growprio", "gp"}, new int[] {8, 2}, true); + if (ix > -1) { + String gp = part.substring(ix).trim(); + char c0 = gp.length() > 0 ? gp.charAt(0) : ' '; + if (c0 == 'x' || c0 == 'y') { // To gandle "gpx", "gpy", "growpriorityx", growpriorityy" + (c0 == 'x' ? cc.getHorizontal() : cc.getVertical()).setGrowPriority(Integer.parseInt(gp.substring(2))); + } else { + String[] grows = toTrimmedTokens(gp, ' '); + cc.getHorizontal().setGrowPriority(Integer.parseInt(grows[0])); + if (grows.length > 1) + cc.getVertical().setGrowPriority(Integer.parseInt(grows[1])); + } + continue; + } + + if (part.startsWith("gap")) { + BoundSize[] gaps = parseGaps(part); + if (gaps[0] != null) + cc.getVertical().setGapBefore(gaps[0]); + if (gaps[1] != null) + cc.getHorizontal().setGapBefore(gaps[1]); + if (gaps[2] != null) + cc.getVertical().setGapAfter(gaps[2]); + if (gaps[3] != null) + cc.getHorizontal().setGapAfter(gaps[3]); + continue; + } + } + + if (c == 'a') { + ix = startsWithLenient(part, new String[] {"aligny", "ay"}, new int[] {6, 2}, true); + if (ix > -1) { + cc.getVertical().setAlign(parseUnitValueOrAlign(part.substring(ix).trim(), false, null)); + continue; + } + + ix = startsWithLenient(part, new String[] {"alignx", "ax"}, new int[] {6, 2}, true); + if (ix > -1) { + cc.getHorizontal().setAlign(parseUnitValueOrAlign(part.substring(ix).trim(), true, null)); + continue; + } + + ix = startsWithLenient(part, "align", 2, true); + if (ix > -1) { + String[] gaps = toTrimmedTokens(part.substring(ix).trim(), ' '); + cc.getHorizontal().setAlign(parseUnitValueOrAlign(gaps[0], true, null)); + if (gaps.length > 1) + cc.getVertical().setAlign(parseUnitValueOrAlign(gaps[1], false, null)); + continue; + } + } + + if ((c == 'x' || c == 'y') && part.length() > 2) { + char c2 = part.charAt(1); + if (c2 == ' ' || (c2 == '2' && part.charAt(2) == ' ')) { + if (cc.getPos() == null) { + cc.setPos(new UnitValue[4]); + } else if (cc.isBoundsInGrid() == false) { + throw new IllegalArgumentException("Can not combine 'position' with 'x/y/x2/y2' keywords."); + } + + int edge = (c == 'x' ? 0 : 1) + (c2 == '2' ? 2 : 0); + UnitValue[] pos = cc.getPos(); + pos[edge] = parseUnitValue(part.substring(2).trim(), null, c == 'x'); + cc.setPos(pos); + cc.setBoundsInGrid(true); + continue; + } + } + + if (c == 'c') { + ix = startsWithLenient(part, "cell", 4, true); + if (ix > -1) { + String[] grs = toTrimmedTokens(part.substring(ix).trim(), ' '); + if (grs.length < 2) + throw new IllegalArgumentException("At least two integers must follow " + part); + cc.setCellX(Integer.parseInt(grs[0])); + cc.setCellY(Integer.parseInt(grs[1])); + if (grs.length > 2) + cc.setSpanX(Integer.parseInt(grs[2])); + if (grs.length > 3) + cc.setSpanY(Integer.parseInt(grs[3])); + continue; + } + } + + if (c == 'p') { + ix = startsWithLenient(part, "pos", 3, true); + if (ix > -1) { + if (cc.getPos() != null && cc.isBoundsInGrid()) + throw new IllegalArgumentException("Can not combine 'pos' with 'x/y/x2/y2' keywords."); + + String[] pos = toTrimmedTokens(part.substring(ix).trim(), ' '); + UnitValue[] bounds = new UnitValue[4]; + for (int j = 0; j < pos.length; j++) + bounds[j] = parseUnitValue(pos[j], null, j % 2 == 0); + + if (bounds[0] == null && bounds[2] == null || bounds[1] == null && bounds[3] == null) + throw new IllegalArgumentException("Both x and x2 or y and y2 can not be null!"); + + cc.setPos(bounds); + cc.setBoundsInGrid(false); + continue; + } + + ix = startsWithLenient(part, "pad", 3, true); + if (ix > -1) { + UnitValue[] p = parseInsets(part.substring(ix).trim(), false); + cc.setPadding(new UnitValue[] { + p[0], + p.length > 1 ? p[1] : null, + p.length > 2 ? p[2] : null, + p.length > 3 ? p[3] : null}); + continue; + } + + ix = startsWithLenient(part, "pushx", 5, true); + if (ix > -1) { + cc.setPushX(parseFloat(part.substring(ix).trim(), ResizeConstraint.WEIGHT_100)); + continue; + } + + ix = startsWithLenient(part, "pushy", 5, true); + if (ix > -1) { + cc.setPushY(parseFloat(part.substring(ix).trim(), ResizeConstraint.WEIGHT_100)); + continue; + } + + ix = startsWithLenient(part, "push", 4, false); + if (ix > -1) { + String[] pushs = toTrimmedTokens(part.substring(ix).trim(), ' '); + cc.setPushX(parseFloat(pushs[0], ResizeConstraint.WEIGHT_100)); + cc.setPushY(parseFloat(pushs.length > 1 ? pushs[1] : "", ResizeConstraint.WEIGHT_100)); + continue; + } + } + + if (c == 't') { + ix = startsWithLenient(part, "tag", 3, true); + if (ix > -1) { + cc.setTag(part.substring(ix).trim()); + continue; + } + } + + if (c == 'w' || c == 'h') { + if (part.equals("wrap")) { + cc.setWrap(true); + continue; + } + + if (part.startsWith("wrap ")) { + String gapSz = part.substring(5).trim(); + cc.setWrapGapSize(parseBoundSize(gapSz, true, true)); + continue; + } + + boolean isHor = c == 'w'; + if (isHor && (part.startsWith("w ") || part.startsWith("width "))) { + String uvStr = part.substring(part.charAt(1) == ' ' ? 2 : 6).trim(); + BoundSize wbs = parseBoundSize(uvStr, false, true); + LayoutUtil.putCCString(wbs, uvStr); + cc.getHorizontal().setSize(wbs); + continue; + } + + if (!isHor && (part.startsWith("h ") || part.startsWith("height "))) { + String uvStr = part.substring(part.charAt(1) == ' ' ? 2 : 7).trim(); + BoundSize hbs = parseBoundSize(uvStr, false, false); + LayoutUtil.putCCString(hbs, uvStr); + cc.getVertical().setSize(hbs); + continue; + } + + if (part.startsWith("wmin ") || part.startsWith("wmax ") || part.startsWith("hmin ") || part.startsWith("hmax ")) { + String uvStr = part.substring(5).trim(); + if (uvStr.length() > 0) { + UnitValue uv = parseUnitValue(uvStr, null, isHor); + boolean isMin = part.charAt(3) == 'n'; + DimConstraint dc = isHor ? cc.getHorizontal() : cc.getVertical(); + dc.setSize(new BoundSize( + isMin ? uv : (dc.getSize() != null ? dc.getSize().getMin() : null), + dc.getSize() != null ? dc.getSize().getPreferred() : null, + isMin ? (dc.getSize() != null ? dc.getSize().getMax() : null) : uv, + uvStr + )); + continue; + } + } + + if (part.equals("west")) { + cc.setDockSide(1); +// cc.getVertical().setGrow(ResizeConstraint.WEIGHT_100); + continue; + } + + if (part.startsWith("hidemode ")) { + cc.setHideMode(Integer.parseInt(part.substring(9))); + continue; + } + } + + if (c == 'i' && part.startsWith("id ")) { + cc.setId(part.substring(3).trim()); + int dIx = cc.getId().indexOf('.'); + if (dIx == 0 || dIx == cc.getId().length() - 1) + throw new IllegalArgumentException("Dot must not be first or last!"); + + continue; + } + + if (c == 'e') { + if (part.equals("east")) { + cc.setDockSide(3); +// cc.getVertical().setGrow(ResizeConstraint.WEIGHT_100); + continue; + } + + if (part.equals("external")) { + cc.setExternal(true); + continue; + } + + ix = startsWithLenient(part, new String[] {"endgroupx", "endgroupy", "egx", "egy"}, new int[] {-1, -1, -1, -1}, true); + if (ix > -1) { + String sg = part.substring(ix).trim(); + char lc = part.charAt(ix - 1); + DimConstraint dc = (lc == 'x' ? cc.getHorizontal() : cc.getVertical()); + dc.setEndGroup(sg); + continue; + } + } + + if (c == 'd') { + if (part.equals("dock north")) { + cc.setDockSide(0); + continue; + } + if (part.equals("dock west")) { + cc.setDockSide(1); + continue; + } + if (part.equals("dock south")) { + cc.setDockSide(2); + continue; + } + if (part.equals("dock east")) { + cc.setDockSide(3); + continue; + } + + if (part.equals("dock center")) { + cc.getHorizontal().setGrow(new Float(100f)); + cc.getVertical().setGrow(new Float(100f)); + continue; + } + } + + UnitValue horAlign = parseAlignKeywords(part, true); + if (horAlign != null) { + cc.getHorizontal().setAlign(horAlign); + continue; + } + + UnitValue verAlign = parseAlignKeywords(part, false); + if (verAlign != null) { + cc.getVertical().setAlign(verAlign); + continue; + } + + throw new IllegalArgumentException("Unknown keyword."); + + } catch (Exception ex) { + throw new IllegalArgumentException("Illegal Constraint: '" + part + "'\n" + ex.getMessage()); + } + } + +// cc = (CC) serializeTest(cc); + + return cc; + } + + /** Parses insets which consists of 1-4 <code>UnitValue</code>s. + * @param s The string to parse. E.g. "10 10 10 10" or "20". If less than 4 groups the last will be used for the missing. + * @param acceptPanel If "panel" and "dialog" should be accepted. They are used to access platform defaults. + * @return An array of length 4 with the parsed insets. + * @throws IllegalArgumentException if the parsing could not be done. + */ + public static UnitValue[] parseInsets(String s, boolean acceptPanel) + { + if (s.length() == 0 || s.equals("dialog") || s.equals("panel")) { + if (acceptPanel == false) + throw new IllegalAccessError("Insets now allowed: " + s + "\n"); + + boolean isPanel = s.startsWith("p"); + UnitValue[] ins = new UnitValue[4]; + for (int j = 0; j < 4; j++) + ins[j] = isPanel ? PlatformDefaults.getPanelInsets(j) : PlatformDefaults.getDialogInsets(j); + + return ins; + } else { + String[] insS = toTrimmedTokens(s, ' '); + UnitValue[] ins = new UnitValue[4]; + for (int j = 0; j < 4; j++) { + UnitValue insSz = parseUnitValue(insS[j < insS.length ? j : insS.length - 1], UnitValue.ZERO, j % 2 == 1); + ins[j] = insSz != null ? insSz : PlatformDefaults.getPanelInsets(j); + } + return ins; + } + } + + /** Parses gaps. + * @param s The string that contains gap information. Should start with "gap". + * @return The gaps as specified in <code>s</code>. Indexed: <code>[top,left,bottom,right][min,pref,max]</code> or + * [before,after][min,pref,max] if <code>oneDim</code> is true. + */ + private static BoundSize[] parseGaps(String s) + { + BoundSize[] ret = new BoundSize[4]; + + int ix = startsWithLenient(s, "gaptop", -1, true); + if (ix > -1) { + s = s.substring(ix).trim(); + ret[0] = parseBoundSize(s, true, false); + return ret; + } + + ix = startsWithLenient(s, "gapleft", -1, true); + if (ix > -1) { + s = s.substring(ix).trim(); + ret[1] = parseBoundSize(s, true, true); + return ret; + } + + ix = startsWithLenient(s, "gapbottom", -1, true); + if (ix > -1) { + s = s.substring(ix).trim(); + ret[2] = parseBoundSize(s, true, false); + return ret; + } + + ix = startsWithLenient(s, "gapright", -1, true); + if (ix > -1) { + s = s.substring(ix).trim(); + ret[3] = parseBoundSize(s, true, true); + return ret; + } + + ix = startsWithLenient(s, "gapbefore", -1, true); + if (ix > -1) { + s = s.substring(ix).trim(); + ret[1] = parseBoundSize(s, true, true); + return ret; + } + + ix = startsWithLenient(s, "gapafter", -1, true); + if (ix > -1) { + s = s.substring(ix).trim(); + ret[3] = parseBoundSize(s, true, true); + return ret; + } + + ix = startsWithLenient(s, new String[] {"gapx", "gapy"}, null, true); + if (ix > -1) { + boolean x = s.charAt(3) == 'x'; + String[] gaps = toTrimmedTokens(s.substring(ix).trim(), ' '); + ret[x ? 1 : 0] = parseBoundSize(gaps[0], true, x); + if (gaps.length > 1) + ret[x ? 3 : 2] = parseBoundSize(gaps[1], true, !x); + return ret; + } + + ix = startsWithLenient(s, "gap ", 1, true); + if (ix > -1) { + String[] gaps = toTrimmedTokens(s.substring(ix).trim(), ' '); + + ret[1] = parseBoundSize(gaps[0], true, true); // left + if (gaps.length > 1) { + ret[3] = parseBoundSize(gaps[1], true, false); // right + if (gaps.length > 2) { + ret[0] = parseBoundSize(gaps[2], true, true); // top + if (gaps.length > 3) + ret[2] = parseBoundSize(gaps[3], true, false); // bottom + } + } + return ret; + } + + throw new IllegalArgumentException("Unknown Gap part: '" + s + "'"); + } + + private static int parseSpan(String s) + { + return s.length() > 0 ? Integer.parseInt(s) : LayoutUtil.INF; + } + + private static Float parseFloat(String s, Float nullVal) + { + return s.length() > 0 ? new Float(Float.parseFloat(s)) : nullVal; + } + + /** Parses a singele "min:pref:max" value. May look something like <code>"10px:20lp:30%"</code> or <code>"pref!"</code>. + * @param s The string to parse. Not <code>null</code>. + * @param isGap If this bound size is a gap (different empty string handling). + * @param isHor If the size is for the horizontal dimension. + * @return A bound size that may be <code>null</code> if the string was "null", "n" or <code>null</code>. + */ + public static BoundSize parseBoundSize(String s, boolean isGap, boolean isHor) + { + if (s.length() == 0 || s.equals("null") || s.equals("n")) + return null; + + boolean push = false; + if (s.endsWith("push")) { + if (isGap == false) + throw new IllegalArgumentException("Only gaps can have 'push' in size. Use as separate keyword for components."); + push = true; + int l = s.length(); + s = s.substring(0, l - (s.endsWith(":push") ? 5 : 4)); + if (s.length() == 0) + return new BoundSize(null, null, null, true, s); + } + + String[] sizes = toTrimmedTokens(s, ':'); + String s0 = sizes[0]; + + if (sizes.length == 1) { + boolean hasEM = s0.endsWith("!"); + if (hasEM) + s0 = s0.substring(0, s0.length() - 1); + UnitValue uv = parseUnitValue(s0, null, isHor); + return new BoundSize(((isGap || hasEM) ? uv : null), uv, (hasEM ? uv : null), push, s); + + } else if (sizes.length == 2) { + return new BoundSize(parseUnitValue(s0, null, isHor), parseUnitValue(sizes[1], null, isHor), null, push, s); + } else if (sizes.length == 3) { + return new BoundSize(parseUnitValue(s0, null, isHor), parseUnitValue(sizes[1], null, isHor), parseUnitValue(sizes[2], null, isHor), push, s); + } else { + throw new IllegalArgumentException("Min:Preferred:Max size section must contain 0, 1 or 2 colons. '" + s + "'"); + } + } + + /** Parses a single unit value that may also be an alignment as parsed by {@link #parseAlignKeywords(String, boolean)}. + * @param s The string to parse. Not <code>null</code>. May look something like <code>"10px"</code> or <code>"5dlu"</code>. + * @param isHor If the value is for the horizontal dimension. + * @param emptyReplacement A replacement if <code>s</code> is empty. May be <code>null</code>. + * @return The parsed unit value. May be <code>null</code>. + */ + public static UnitValue parseUnitValueOrAlign(String s, boolean isHor, UnitValue emptyReplacement) + { + if (s.length() == 0) + return emptyReplacement; + + UnitValue align = parseAlignKeywords(s, isHor); + if (align != null) + return align; + + return parseUnitValue(s, emptyReplacement, isHor); + } + + /** Parses a single unit value. E.g. "10px" or "5in" + * @param s The string to parse. Not <code>null</code>. May look something like <code>"10px"</code> or <code>"5dlu"</code>. + * @param isHor If the value is for the horizontal dimension. + * @return The parsed unit value. <code>null</code> is empty string, + */ + public static UnitValue parseUnitValue(String s, boolean isHor) + { + return parseUnitValue(s, null, isHor); + } + + /** Parses a single unit value. + * @param s The string to parse. May be <code>null</code>. May look something like <code>"10px"</code> or <code>"5dlu"</code>. + * @param emptyReplacement A replacement <code>s</code> is empty or <code>null</code>. May be <code>null</code>. + * @param isHor If the value is for the horizontal dimension. + * @return The parsed unit value. May be <code>null</code>. + */ + private static UnitValue parseUnitValue(String s, UnitValue emptyReplacement, boolean isHor) + { + if (s == null || s.length() == 0) + return emptyReplacement; + + String cs = s; // Save creation string. + char c0 = s.charAt(0); + + // Remove start and end parentheses, if there. + if (c0 == '(' && s.charAt(s.length() - 1) == ')') + s = s.substring(1, s.length() - 1); + + if (c0 == 'n' && (s.equals("null") || s.equals("n"))) + return null; + + if (c0 == 'i' && s.equals("inf")) + return UnitValue.INF; + + int oper = getOper(s); + boolean inline = oper == UnitValue.ADD || oper == UnitValue.SUB || oper == UnitValue.MUL || oper == UnitValue.DIV; + + if (oper != UnitValue.STATIC) { // It is a multi-value + + String[] uvs; + if (inline == false) { // If the format is of type "opr(xxx,yyy)" (compared to in-line "10%+15px") + String sub = s.substring(4, s.length() - 1).trim(); + uvs = toTrimmedTokens(sub, ','); + if (uvs.length == 1) + return parseUnitValue(sub, null, isHor); + } else { + char delim; + if (oper == UnitValue.ADD) { + delim = '+'; + } else if (oper == UnitValue.SUB) { + delim = '-'; + } else if (oper == UnitValue.MUL) { + delim = '*'; + } else { // div left + delim = '/'; + } + uvs = toTrimmedTokens(s, delim); + if (uvs.length > 2) { // More than one +-*/. + String last = uvs[uvs.length - 1]; + String first = s.substring(0, s.length() - last.length() - 1); + uvs = new String[] {first, last}; + } + } + + if (uvs.length != 2) + throw new IllegalArgumentException("Malformed UnitValue: '" + s + "'"); + + UnitValue sub1 = parseUnitValue(uvs[0], null, isHor); + UnitValue sub2 = parseUnitValue(uvs[1], null, isHor); + + if (sub1 == null || sub2 == null) + throw new IllegalArgumentException("Malformed UnitValue. Must be two sub-values: '" + s + "'"); + + return new UnitValue(isHor, oper, sub1, sub2, cs); + } else { + try { + String[] numParts = getNumTextParts(s); + float value = numParts[0].length() > 0 ? Float.parseFloat(numParts[0]) : 1; // e.g. "related" has no number part.. + + return new UnitValue(value, numParts[1], isHor, oper, cs); + + } catch(Exception e) { + throw new IllegalArgumentException("Malformed UnitValue: '" + s + "'"); + } + } + } + + /** Parses alignment keywords and returns the approprieate <code>UnitValue</code>. + * @param s The string to parse. Not <code>null</code>. + * @param isHor If alignments for horizontal is checked. <code>false</code> means vertical. + * @return The unit value or <code>null</code> if not recognized (no exception). + */ + static UnitValue parseAlignKeywords(String s, boolean isHor) + { + if (startsWithLenient(s, "center", 1, false) != -1) + return UnitValue.CENTER; + + if (isHor) { + if (startsWithLenient(s, "left", 1, false) != -1) + return UnitValue.LEFT; + + if (startsWithLenient(s, "right", 1, false) != -1) + return UnitValue.RIGHT; + + if (startsWithLenient(s, "leading", 4, false) != -1) + return UnitValue.LEADING; + + if (startsWithLenient(s, "trailing", 5, false) != -1) + return UnitValue.TRAILING; + + if (startsWithLenient(s, "label", 5, false) != -1) + return UnitValue.LABEL; + + } else { + + if (startsWithLenient(s, "baseline", 4, false) != -1) + return UnitValue.BASELINE_IDENTITY; + + if (startsWithLenient(s, "top", 1, false) != -1) + return UnitValue.TOP; + + if (startsWithLenient(s, "bottom", 1, false) != -1) + return UnitValue.BOTTOM; + } + + return null; + } + + /** Splits a text-number combination such as "hello 10.0" into <code>{"hello", "10.0"}</code>. + * @param s The string to split. Not <code>null</code>. Needs be be resonably formatted since the method + * only finds the first 0-9 or . and cuts the string in half there. + * @return Always length 2 and no <code>null</code> elements. Elements are "" if no part found. + */ + private static String[] getNumTextParts(String s) + { + for (int i = 0, iSz = s.length(); i < iSz; i++) { + char c = s.charAt(i); + if (c == ' ') + throw new IllegalArgumentException("Space in UnitValue: '" + s + "'"); + + if ((c < '0' || c > '9') && c != '.' && c != '-') + return new String[] {s.substring(0, i).trim(), s.substring(i).trim()}; + } + return new String[] {s, ""}; + } + + /** Returns the operation depending on the start character. + * @param s The string to check. Not <code>null</code>. + * @return E.g. UnitValue.ADD, UnitValue.SUB or UnitValue.STATIC. Returns negative value for in-line operations. + */ + private static int getOper(String s) + { + int len = s.length(); + if (len < 3) + return UnitValue.STATIC; + + if (len > 5 && s.charAt(3) == '(' && s.charAt(len - 1) == ')') { + if (s.startsWith("min(")) + return UnitValue.MIN; + + if (s.startsWith("max(")) + return UnitValue.MAX; + + if (s.startsWith("mid(")) + return UnitValue.MID; + } + + // Try in-line add/sub. E.g. "pref+10px". + for (int j = 0; j < 2; j++) { // First +- then */ (precedence) + for (int i = len - 1, p = 0; i > 0; i--) { + char c = s.charAt(i); + if (c == ')') { + p++; + } else if (c == '(') { + p--; + } else if (p == 0) { + if (j == 0) { + if (c == '+') + return UnitValue.ADD; + if (c == '-') + return UnitValue.SUB; + } else { + if (c == '*') + return UnitValue.MUL; + if (c == '/') + return UnitValue.DIV; + } + } + } + } + return UnitValue.STATIC; + } + + /** Returns if a string shares at least a specified numbers starting characters with a number of matches. + * <p> + * This method just excercises {@link #startsWithLenient(String, String, int, boolean)} with every one of + * <code>matches</code> and <code>minChars</code>. + * @param s The string to check. Not <code>null</code>. + * @param matches A number of possible starts for <code>s</code>. + * @param minChars The mimimum number of characters to match for every element in <code>matches</code>. Needs + * to be of same length as <code>matches</code>. Can be <code>null</code>. + * @param acceptTrailing If after the required number of charecters are matched onrecognized characters that are not + * in one of the the <code>matches</code> string should be accepted. For instance if "abczz" should be matched with + * "abcdef" and min chars 3. + * @return The index of the first unmatched character if <code>minChars</code> was reached or <code>-1</code> if a match was not + * found. + */ + private static int startsWithLenient(String s, String[] matches, int[] minChars, boolean acceptTrailing) + { + for (int i = 0; i < matches.length; i++) { + int minChar = minChars != null ? minChars[i] : -1; + int ix = startsWithLenient(s, matches[i], minChar, acceptTrailing); + if (ix > -1) + return ix; + } + return -1; + } + + /** Returns if a string shares at least a specified numbers starting characters with a match. + * @param s The string to check. Not <code>null</code> and must be trimmed. + * @param match The possible start for <code>s</code>. Not <code>null</code> and must be trimmed. + * @param minChars The mimimum number of characters to match to <code>s</code> for it this to be considered a match. -1 means + * the full length of <code>match</code>. + * @param acceptTrailing If after the required number of charecters are matched unrecognized characters that are not + * in one of the the <code>matches</code> string should be accepted. For instance if "abczz" should be matched with + * "abcdef" and min chars 3. + * @return The index of the first unmatched character if <code>minChars</code> was reached or <code>-1</code> if a match was not + * found. + */ + private static int startsWithLenient(String s, String match, int minChars, boolean acceptTrailing) + { + if (s.charAt(0) != match.charAt(0)) // Fast sanity check. + return -1; + + if (minChars == -1) + minChars = match.length(); + + int sSz = s.length(); + if (sSz < minChars) + return -1; + + int mSz = match.length(); + int sIx = 0; + for (int mIx = 0; mIx < mSz; sIx++, mIx++) { + while (sIx < sSz && (s.charAt(sIx) == ' ' || s.charAt(sIx) == '_')) // Disregard spaces and _ + sIx++; + + if (sIx >= sSz || s.charAt(sIx) != match.charAt(mIx)) + return mIx >= minChars && (acceptTrailing || sIx >= sSz) && (sIx >= sSz || s.charAt(sIx - 1) == ' ') ? sIx : -1; + } +// return (sIx >= sSz || acceptTrailing) && (sIx >= sSz || s.charAt(sIx) == ' ') ? sIx : -1; + return sIx >= sSz || acceptTrailing ||s.charAt(sIx) == ' ' ? sIx : -1; + } + + /** Parses a string and returns it in those parts of the string that are separated with a <code>sep</code> character. + * <p> + * separator characters within parentheses will not be counted or handled in any way, whatever the depth. + * @param s The string to parse. If it starts and/or ends with a <code>sep</code> the first and/or last element returned will be "". If + * two <code>sep</code> are next to eachother and empty element will be "between" the periods. The <code>sep</code> themselves will never be returned. + * @param sep The separator char. + * @return Those parts of the string that are separated with <code>sep</code>. Never null and at least of size 1 + */ + private final static String[] toTrimmedTokens(String s, char sep) + { + int toks = 0, sSize = s.length(); + + // Count the sep:s + int p = 0; + for(int i = 0; i < sSize; i++) { + char c = s.charAt(i); + if (c == '(') { + p++; + } else if (c == ')') { + p--; + } else if (p == 0 && c == sep) { + toks++; + } + if (p < 0) + throw new IllegalArgumentException("Unbalanced parentheses: '" + s + "'"); + } + if (p != 0) + throw new IllegalArgumentException("Unbalanced parentheses: '" + s + "'"); + + if (toks == 0) + return new String [] {s.trim()}; + + String[] retArr = new String[toks + 1]; + + int st = 0, pNr = 0; + p = 0; + for (int i = 0; i < sSize; i++) { + + char c = s.charAt(i); + if (c == '(') { + p++; + } else if (c == ')') { + p--; + } else if (p == 0 && c == sep) { + retArr[pNr++] = s.substring(st, i).trim(); + st = i + 1; + } + } + + retArr[pNr++] = s.substring(st, sSize).trim(); + return retArr; + } + + /** Parses "AAA[BBB]CCC[DDD]EEE" into {"AAA", "BBB", "CCC", "DDD", "EEE", "FFF"}. Handles empty parts. Will always start and end outside + * a [] block so that the number of returned elemets will always be uneven and at least of length 3. + * <p> + * "|" is interprated as "][". + * @param s The string. Might be "" but not null. Should be trimmed. + * @return The string divided into elements. Never <code>null</code> and at least of length 3. + * @throws IllegalArgumentException If a [] mismatch of some kind. (If not same [ as ] count or if the interleave.) + */ + private final static ArrayList<String> getRowColAndGapsTrimmed(String s) + { + if (s.indexOf('|') != -1) + s = s.replaceAll("\\|", "]["); + + ArrayList<String> retList = new ArrayList<String>(Math.max(s.length() >> 2 + 1, 3)); // Aprox return length. + int s0 = 0, s1 = 0; // '[' and ']' count. + int st = 0; // Start of "next token to add". + for (int i = 0, iSz = s.length(); i < iSz; i++) { + char c = s.charAt(i); + if (c == '[') { + s0++; + } else if (c == ']') { + s1++; + } else { + continue; + } + + if (s0 != s1 && (s0 - 1) != s1) + break; // Wrong [ or ] found. Break for throw. + + retList.add(s.substring(st, i).trim()); + st = i + 1; + } + if (s0 != s1) + throw new IllegalArgumentException("'[' and ']' mismatch in row/column format string: " + s); + + if (s0 == 0) { + retList.add(""); + retList.add(s); + retList.add(""); + } else if (retList.size() % 2 == 0) { + retList.add(s.substring(st, s.length())); + } + + return retList; + } + + /** Makes <code>null</code> "", trimms and converts to lower case. + * @param s The string + * @return Not null. + */ + public static final String prepare(String s) + { + return s != null ? s.trim().toLowerCase() : ""; + } + +// /** Tests to serialize and deserialize the object with both XMLEncoder/Decoder and through Serializable +// * @param o The object to serialize +// * @return The same object after a tri through the process. +// */ +// public static final Object serializeTest(Object o) +// { +// try { +// ByteArrayOutputStream barr = new ByteArrayOutputStream(); +// XMLEncoder enc = new XMLEncoder(barr); +// enc.writeObject(o); +// enc.close(); +// +// XMLDecoder dec = new XMLDecoder(new ByteArrayInputStream(barr.toByteArray())); +// o = dec.readObject(); +// dec.close(); +// } catch (Exception e) { +// e.printStackTrace(); +// } +// +// try { +// ByteArrayOutputStream barr = new ByteArrayOutputStream(); +// ObjectOutputStream oos = new ObjectOutputStream(barr); +// oos.writeObject(o); +// oos.close(); +// +// ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(barr.toByteArray())); +// o = ois.readObject(); +// ois.close(); +// } catch (Exception e) { +// e.printStackTrace(); +// } +// +// return o; +// } +} diff --git a/prototypes/miglayout/net/miginfocom/layout/ContainerWrapper.java b/prototypes/miglayout/net/miginfocom/layout/ContainerWrapper.java index 65428add..8f801705 100644 --- a/prototypes/miglayout/net/miginfocom/layout/ContainerWrapper.java +++ b/prototypes/miglayout/net/miginfocom/layout/ContainerWrapper.java @@ -1,69 +1,69 @@ -package net.miginfocom.layout;
-/*
- * License (BSD):
- * ==============
- *
- * Copyright (c) 2004, Mikael Grev, MiG InfoCom AB. (miglayout (at) miginfocom (dot) com)
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification,
- * are permitted provided that the following conditions are met:
- * Redistributions of source code must retain the above copyright notice, this list
- * of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above copyright notice, this
- * list of conditions and the following disclaimer in the documentation and/or other
- * materials provided with the distribution.
- * Neither the name of the MiG InfoCom AB nor the names of its contributors may be
- * used to endorse or promote products derived from this software without specific
- * prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
- * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
- * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
- * OF SUCH DAMAGE.
- *
- * @version 1.0
- * @author Mikael Grev, MiG InfoCom AB
- * Date: 2006-sep-08
- */
-
-/** A class that wraps a container that contains components.
- */
-public interface ContainerWrapper extends ComponentWrapper
-{
- /** Returns the components of the container that wrapper is wrapping.
- * @return The components of the container that wrapper is wrapping. Never <code>null</code>.
- */
- public abstract ComponentWrapper[] getComponents();
-
- /** Returns the number of components that this parent has.
- * @return The number of components that this parent has.
- */
- public abstract int getComponentCount();
-
- /** Returns the <code>LayoutHandler</code> (in Swing terms) that is handling the layout of this container.
- * If there exist no such class the method should return the same as {@link #getComponent()}, which is the
- * container itself.
- * @return The layout handler instance. Never <code>null</code>.
- */
- public abstract Object getLayout();
-
- /** Returns if this container is using left-to-right component ordering.
- * @return If this container is using left-to-right component ordering.
- */
- public abstract boolean isLeftToRight();
-
- /** Paints a cell to indicate where it is.
- * @param x The x coordinate to start the drwaing.
- * @param y The x coordinate to start the drwaing.
- * @param width The width to draw/fill
- * @param height The height to draw/fill
- */
- public abstract void paintDebugCell(int x, int y, int width, int height);
-}
+package net.miginfocom.layout; +/* + * License (BSD): + * ============== + * + * Copyright (c) 2004, Mikael Grev, MiG InfoCom AB. (miglayout (at) miginfocom (dot) com) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright notice, this list + * of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * Neither the name of the MiG InfoCom AB nor the names of its contributors may be + * used to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * @version 1.0 + * @author Mikael Grev, MiG InfoCom AB + * Date: 2006-sep-08 + */ + +/** A class that wraps a container that contains components. + */ +public interface ContainerWrapper extends ComponentWrapper +{ + /** Returns the components of the container that wrapper is wrapping. + * @return The components of the container that wrapper is wrapping. Never <code>null</code>. + */ + public abstract ComponentWrapper[] getComponents(); + + /** Returns the number of components that this parent has. + * @return The number of components that this parent has. + */ + public abstract int getComponentCount(); + + /** Returns the <code>LayoutHandler</code> (in Swing terms) that is handling the layout of this container. + * If there exist no such class the method should return the same as {@link #getComponent()}, which is the + * container itself. + * @return The layout handler instance. Never <code>null</code>. + */ + public abstract Object getLayout(); + + /** Returns if this container is using left-to-right component ordering. + * @return If this container is using left-to-right component ordering. + */ + public abstract boolean isLeftToRight(); + + /** Paints a cell to indicate where it is. + * @param x The x coordinate to start the drwaing. + * @param y The x coordinate to start the drwaing. + * @param width The width to draw/fill + * @param height The height to draw/fill + */ + public abstract void paintDebugCell(int x, int y, int width, int height); +} diff --git a/prototypes/miglayout/net/miginfocom/layout/DimConstraint.java b/prototypes/miglayout/net/miginfocom/layout/DimConstraint.java index 47c1021c..a5b1276d 100644 --- a/prototypes/miglayout/net/miginfocom/layout/DimConstraint.java +++ b/prototypes/miglayout/net/miginfocom/layout/DimConstraint.java @@ -1,466 +1,466 @@ -package net.miginfocom.layout;
-
-import java.io.*;
-/*
- * License (BSD):
- * ==============
- *
- * Copyright (c) 2004, Mikael Grev, MiG InfoCom AB. (miglayout (at) miginfocom (dot) com)
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification,
- * are permitted provided that the following conditions are met:
- * Redistributions of source code must retain the above copyright notice, this list
- * of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above copyright notice, this
- * list of conditions and the following disclaimer in the documentation and/or other
- * materials provided with the distribution.
- * Neither the name of the MiG InfoCom AB nor the names of its contributors may be
- * used to endorse or promote products derived from this software without specific
- * prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
- * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
- * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
- * OF SUCH DAMAGE.
- *
- * @version 1.0
- * @author Mikael Grev, MiG InfoCom AB
- * Date: 2006-sep-08
- */
-
-/** A simple value holder for a constraint for one dimension.
- */
-public final class DimConstraint implements Externalizable
-{
- /** How this entity can be resized in the dimension that this constraint represents.
- */
- final ResizeConstraint resize = new ResizeConstraint();
-
- // Look at the properties' getter/setter methods for exmplanation
-
- private String sizeGroup = null; // A "context" compared with equals.
-
- private BoundSize size = null; // Min, pref, max. May be null.
-
- private BoundSize gapBefore = null, gapAfter = null;
-
- private UnitValue align = null;
-
-
- // ************** Only applicable on components! *******************
-
- private String endGroup = null; // A "context" compared with equals.
-
-
- // ************** Only applicable on rows/columns! *******************
-
- private boolean fill = false;
-
- private boolean noGrid = false;
-
- /** Empty constructor.
- */
- public DimConstraint()
- {
- }
-
- /** Returns the grow priority. Relative priority is used for determining which entities gets the extra space first.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @return The grow priority.
- */
- public int getGrowPriority()
- {
- return resize.growPrio;
- }
-
- /** Sets the grow priority. Relative priority is used for determining which entities gets the extra space first.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @param p The new grow priority.
- */
- public void setGrowPriority(int p)
- {
- resize.growPrio = p;
- }
-
- /** Returns the grow weight.<p>
- * Grow weight is how flexilble the entity should be, relative to other entities, when it comes to growing. <code>null</code> or
- * zero mean it will never grow. An entity that has twise the grow weight compared to another entity will get twice
- * as much of available space.
- * <p>
- * GrowWeight are only compared within the same GrowPrio.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @return The current grow weight.
- */
- public Float getGrow()
- {
- return resize.grow;
- }
-
- /** Sets the grow weight.<p>
- * Grow weight is how flexilble the entity should be, relative to other entities, when it comes to growing. <code>null</code> or
- * zero mean it will never grow. An entity that has twise the grow weight compared to another entity will get twice
- * as much of available space.
- * <p>
- * GrowWeight are only compared within the same GrowPrio.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @param weight The new grow weight.
- */
- public void setGrow(Float weight)
- {
- resize.grow = weight;
- }
-
- /** Returns the shrink priority. Relative priority is used for determining which entities gets smaller first when space is scarse.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @return The shrink priority.
- */
- public int getShrinkPriority()
- {
- return resize.shrinkPrio;
- }
-
- /** Sets the shrink priority. Relative priority is used for determining which entities gets smaller first when space is scarse.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @param p The new shrink priority.
- */
- public void setShrinkPriority(int p)
- {
- resize.shrinkPrio = p;
- }
-
- /** Returns the shrink priority. Relative priority is used for determining which entities gets smaller first when space is scarse.
- * Shrink weight is how flexilble the entity should be, relative to other entities, when it comes to shrinking. <code>null</code> or
- * zero mean it will never shrink (default). An entity that has twise the shrink weight compared to another entity will get twice
- * as much of available space.
- * <p>
- * Shrink(Weight) are only compared within the same ShrinkPrio.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @return The current shrink weight.
- */
- public Float getShrink()
- {
- return resize.shrink;
- }
-
- /** Sets the shrink priority. Relative priority is used for determining which entities gets smaller first when space is scarse.
- * Shrink weight is how flexilble the entity should be, relative to other entities, when it comes to shrinking. <code>null</code> or
- * zero mean it will never shrink (default). An entity that has twise the shrink weight compared to another entity will get twice
- * as much of available space.
- * <p>
- * Shrink(Weight) are only compared within the same ShrinkPrio.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @param weight The new shrink weight.
- */
- public void setShrink(Float weight)
- {
- resize.shrink = weight;
- }
-
- public UnitValue getAlignOrDefault(boolean isCols)
- {
- if (align != null)
- return align;
-
- return isCols ? UnitValue.LEADING : UnitValue.CENTER;
- }
-
- /** Returns the alignment used either as a default value for sub-entities or for this entity.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @return The alignment.
- */
- public UnitValue getAlign()
- {
- return align;
- }
-
- /** Sets the alignment used wither as a default value for sub-entities or for this entity.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @param uv The new shrink priority. E.g. {@link UnitValue#CENTER} or {@link net.miginfocom.layout.UnitValue#LEADING}.
- */
- public void setAlign(UnitValue uv)
- {
- this.align = uv;
- }
-
- /** Returns the gap after this entitiy. The gap is an empty space and can have a min/preferred/maximum size so that it can shrink and
- * grow depending on available space. Gaps are against other entities' edges and not against other entities' gaps.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @return The gap after this entitiy
- */
- public BoundSize getGapAfter()
- {
- return gapAfter;
- }
-
- /** Sets the gap after this entitiy. The gap is an empty space and can have a min/preferred/maximum size so that it can shrink and
- * grow depending on available space. Gaps are against other entities' edges and not against other entities' gaps.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @param size The new gap.
- * @see net.miginfocom.layout.ConstraintParser#parseBoundSize(String, boolean, boolean).
- */
- public void setGapAfter(BoundSize size)
- {
- this.gapAfter = size;
- }
-
- boolean hasGapAfter()
- {
- return gapAfter != null && gapAfter.isUnset() == false;
- }
-
- boolean isGapAfterPush()
- {
- return gapAfter != null && gapAfter.getGapPush();
- }
-
- /** Returns the gap before this entitiy. The gap is an empty space and can have a min/preferred/maximum size so that it can shrink and
- * grow depending on available space. Gaps are against other entities' edges and not against other entities' gaps.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @return The gap before this entitiy
- */
- public BoundSize getGapBefore()
- {
- return gapBefore;
- }
-
- /** Sets the gap before this entitiy. The gap is an empty space and can have a min/preferred/maximum size so that it can shrink and
- * grow depending on available space. Gaps are against other entities' edges and not against other entities' gaps.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @param size The new gap.
- * @see net.miginfocom.layout.ConstraintParser#parseBoundSize(String, boolean, boolean).
- */
- public void setGapBefore(BoundSize size)
- {
- this.gapBefore = size;
- }
-
- boolean hasGapBefore()
- {
- return gapBefore != null && gapBefore.isUnset() == false;
- }
-
- boolean isGapBeforePush()
- {
- return gapBefore != null && gapBefore.getGapPush();
- }
-
- /** Returns the min/prerefferd/max size for the entity in the dimension that this object describes.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @return The current size. May be <code>null</code>.
- * @see net.miginfocom.layout.ConstraintParser#parseBoundSize(String, boolean, boolean).
- */
- public BoundSize getSize()
- {
- return size;
- }
-
- /** Sets the min/prerefferd/max size for the eintity in the dimension that this object describes.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @param size The new size. May be <code>null</code>.
- */
- public void setSize(BoundSize size)
- {
- this.size = size;
- }
-
- /** Returns the size group that this entitiy should be in for the demension that this object is describing.
- * If this constraint is in a size group that is specified here. <code>null</code> means no size group
- * and all other values are legal. Comparison with .equals(). Components/columnss/rows in the same size group
- * will have the same min/preferred/max size; that of the largest in the group for the first two and the
- * smallest for max.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @return The current size group. May be <code>null</code>.
- */
- public String getSizeGroup()
- {
- return sizeGroup;
- }
-
- /** Sets the size group that this entitiy should be in for the demension that this object is describing.
- * If this constraint is in a size group that is specified here. <code>null</code> means no size group
- * and all other values are legal. Comparison with .equals(). Components/columnss/rows in the same size group
- * will have the same min/preferred/max size; that of the largest in the group for the first two and the
- * smallest for max.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @param s The new size group. <code>null</code> disables size grouping.
- */
- public void setSizeGroup(String s)
- {
- sizeGroup = s;
- }
-
- // ************** Only applicable on components ! *******************
-
- /** Returns the end group that this entitiy should be in for the demension that this object is describing.
- * If this constraint is in an end group that is specified here. <code>null</code> means no end group
- * and all other values are legal. Comparison with .equals(). Components in the same end group
- * will have the same end coordinate.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @return The current end group. <code>null</code> may be returned.
- */
- public String getEndGroup()
- {
- return endGroup;
- }
-
- /** Sets the end group that this entitiy should be in for the demension that this object is describing.
- * If this constraint is in an end group that is specified here. <code>null</code> means no end group
- * and all other values are legal. Comparison with .equals(). Components in the same end group
- * will have the same end coordinate.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @param s The new end group. <code>null</code> disables end grouping.
- */
- public void setEndGroup(String s)
- {
- endGroup = s;
- }
-
- // ************** Not applicable on components below ! *******************
-
- /** Returns if the component in the row/column that this constraint should default be grown in the same dimension that
- * this constraint represents (width for column and height for a row).
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @return code>true</code> means that components should grow.
- */
- public boolean isFill()
- {
- return fill;
- }
-
- /** Sets if the component in the row/column that this constraint should default be grown in the same dimension that
- * this constraint represents (width for column and height for a row).
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @param b <code>true</code> means that components should grow.
- */
- public void setFill(boolean b)
- {
- fill = b;
- }
-
- /** Returns if the row/column should default to flow and not to grid behaviour. This means that the whole row/column
- * will be one cell and all components will end up in that cell.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @return <code>true</code> means that the whole row/column should be one cell.
- */
- public boolean isNoGrid()
- {
- return noGrid;
- }
-
- /** Sets if the row/column should default to flow and not to grid behaviour. This means that the whole row/column
- * will be one cell and all components will end up in that cell.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @param b <code>true</code> means that the whole row/column should be one cell.
- */
- public void setNoGrid(boolean b)
- {
- this.noGrid = b;
- }
-
- /** Returns the gaps as pixel values.
- * @param parent The parent. Used to get the pixel values.
- * @param defGap The default gap to use if there is no gap set on this object (i.e. it is null).
- * @param refSize The reference size used to get the pixel sizes.
- * @param before IF it is the gap before rather than the gap after to return.
- * @return The [min,preferred,max] sizes for the specified gap. Uses {@link net.miginfocom.layout.LayoutUtil#NOT_SET}
- * for gap sizes that are <code>null</code>. Returns <code>null</code> if there was no gap specified. A new and free to use array.
- */
- int[] getRowGaps(ContainerWrapper parent, BoundSize defGap, int refSize, boolean before)
- {
- BoundSize gap = before ? gapBefore : gapAfter;
- if (gap == null || gap.isUnset())
- gap = defGap;
-
- if (gap == null || gap.isUnset())
- return null;
-
- int[] ret = new int[3];
- for (int i = LayoutUtil.MIN; i <= LayoutUtil.MAX; i++) {
- UnitValue uv = gap.getSize(i);
- ret[i] = uv != null ? uv.getPixels(refSize, parent, null) : LayoutUtil.NOT_SET;
- }
- return ret;
- }
-
- /** Returns the gaps as pixel values.
- * @param parent The parent. Used to get the pixel values.
- * @param comp The component that the gap is for. If not for a component it is <code>null</code>.
- * @param adjGap The gap that the adjacent component, if any, has towards <code>comp</code>.
- * @param adjacentComp The adjacent component if any. May be <code>null</code>.
- * @param refSize The reference size used to get the pixel sizes.
- * @param adjacentSide Whan side the <code>adjacentComp</code> is on. 0 = top, 1 = left, 2 = bottom, 3 = right.
- * @param tag The tag string that the component might be tagged with in the component constraints. May be <code>null</code>.
- * @param isLTR If it is left-to-right.
- * @return The [min,preferred,max] sizes for the specified gap. Uses {@link net.miginfocom.layout.LayoutUtil#NOT_SET}
- * for gap sizes that are <code>null</code>. Returns <code>null</code> if there was no gap specified. A new and free to use array.
- */
- int[] getComponentGaps(ContainerWrapper parent, ComponentWrapper comp, BoundSize adjGap, ComponentWrapper adjacentComp, String tag, int refSize, int adjacentSide, boolean isLTR)
- {
- BoundSize gap = adjacentSide < 2 ? gapBefore : gapAfter;
-
- boolean hasGap = gap != null && gap.getGapPush();
- if ((gap == null || gap.isUnset()) && (adjGap == null || adjGap.isUnset()) && comp != null)
- gap = PlatformDefaults.getDefaultComponentGap(comp, adjacentComp, adjacentSide + 1, tag, isLTR);
-
- if (gap == null)
- return hasGap ? new int[] {0, 0, LayoutUtil.NOT_SET} : null;
-
- int[] ret = new int[3];
- for (int i = LayoutUtil.MIN; i <= LayoutUtil.MAX; i++) {
- UnitValue uv = gap.getSize(i);
- ret[i] = uv != null ? uv.getPixels(refSize, parent, null) : LayoutUtil.NOT_SET;
- }
- return ret;
- }
-
- // ************************************************
- // Persistence Delegate and Serializable combined.
- // ************************************************
-
- private Object readResolve() throws ObjectStreamException
- {
- return LayoutUtil.getSerializedObject(this);
- }
-
- public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException
- {
- LayoutUtil.setSerializedObject(this, LayoutUtil.readAsXML(in));
- }
-
- public void writeExternal(ObjectOutput out) throws IOException
- {
- if (getClass() == DimConstraint.class)
- LayoutUtil.writeAsXML(out, this);
- }
-}
+package net.miginfocom.layout; + +import java.io.*; +/* + * License (BSD): + * ============== + * + * Copyright (c) 2004, Mikael Grev, MiG InfoCom AB. (miglayout (at) miginfocom (dot) com) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright notice, this list + * of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * Neither the name of the MiG InfoCom AB nor the names of its contributors may be + * used to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * @version 1.0 + * @author Mikael Grev, MiG InfoCom AB + * Date: 2006-sep-08 + */ + +/** A simple value holder for a constraint for one dimension. + */ +public final class DimConstraint implements Externalizable +{ + /** How this entity can be resized in the dimension that this constraint represents. + */ + final ResizeConstraint resize = new ResizeConstraint(); + + // Look at the properties' getter/setter methods for exmplanation + + private String sizeGroup = null; // A "context" compared with equals. + + private BoundSize size = null; // Min, pref, max. May be null. + + private BoundSize gapBefore = null, gapAfter = null; + + private UnitValue align = null; + + + // ************** Only applicable on components! ******************* + + private String endGroup = null; // A "context" compared with equals. + + + // ************** Only applicable on rows/columns! ******************* + + private boolean fill = false; + + private boolean noGrid = false; + + /** Empty constructor. + */ + public DimConstraint() + { + } + + /** Returns the grow priority. Relative priority is used for determining which entities gets the extra space first. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @return The grow priority. + */ + public int getGrowPriority() + { + return resize.growPrio; + } + + /** Sets the grow priority. Relative priority is used for determining which entities gets the extra space first. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @param p The new grow priority. + */ + public void setGrowPriority(int p) + { + resize.growPrio = p; + } + + /** Returns the grow weight.<p> + * Grow weight is how flexilble the entity should be, relative to other entities, when it comes to growing. <code>null</code> or + * zero mean it will never grow. An entity that has twise the grow weight compared to another entity will get twice + * as much of available space. + * <p> + * GrowWeight are only compared within the same GrowPrio. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @return The current grow weight. + */ + public Float getGrow() + { + return resize.grow; + } + + /** Sets the grow weight.<p> + * Grow weight is how flexilble the entity should be, relative to other entities, when it comes to growing. <code>null</code> or + * zero mean it will never grow. An entity that has twise the grow weight compared to another entity will get twice + * as much of available space. + * <p> + * GrowWeight are only compared within the same GrowPrio. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @param weight The new grow weight. + */ + public void setGrow(Float weight) + { + resize.grow = weight; + } + + /** Returns the shrink priority. Relative priority is used for determining which entities gets smaller first when space is scarse. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @return The shrink priority. + */ + public int getShrinkPriority() + { + return resize.shrinkPrio; + } + + /** Sets the shrink priority. Relative priority is used for determining which entities gets smaller first when space is scarse. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @param p The new shrink priority. + */ + public void setShrinkPriority(int p) + { + resize.shrinkPrio = p; + } + + /** Returns the shrink priority. Relative priority is used for determining which entities gets smaller first when space is scarse. + * Shrink weight is how flexilble the entity should be, relative to other entities, when it comes to shrinking. <code>null</code> or + * zero mean it will never shrink (default). An entity that has twise the shrink weight compared to another entity will get twice + * as much of available space. + * <p> + * Shrink(Weight) are only compared within the same ShrinkPrio. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @return The current shrink weight. + */ + public Float getShrink() + { + return resize.shrink; + } + + /** Sets the shrink priority. Relative priority is used for determining which entities gets smaller first when space is scarse. + * Shrink weight is how flexilble the entity should be, relative to other entities, when it comes to shrinking. <code>null</code> or + * zero mean it will never shrink (default). An entity that has twise the shrink weight compared to another entity will get twice + * as much of available space. + * <p> + * Shrink(Weight) are only compared within the same ShrinkPrio. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @param weight The new shrink weight. + */ + public void setShrink(Float weight) + { + resize.shrink = weight; + } + + public UnitValue getAlignOrDefault(boolean isCols) + { + if (align != null) + return align; + + return isCols ? UnitValue.LEADING : UnitValue.CENTER; + } + + /** Returns the alignment used either as a default value for sub-entities or for this entity. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @return The alignment. + */ + public UnitValue getAlign() + { + return align; + } + + /** Sets the alignment used wither as a default value for sub-entities or for this entity. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @param uv The new shrink priority. E.g. {@link UnitValue#CENTER} or {@link net.miginfocom.layout.UnitValue#LEADING}. + */ + public void setAlign(UnitValue uv) + { + this.align = uv; + } + + /** Returns the gap after this entitiy. The gap is an empty space and can have a min/preferred/maximum size so that it can shrink and + * grow depending on available space. Gaps are against other entities' edges and not against other entities' gaps. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @return The gap after this entitiy + */ + public BoundSize getGapAfter() + { + return gapAfter; + } + + /** Sets the gap after this entitiy. The gap is an empty space and can have a min/preferred/maximum size so that it can shrink and + * grow depending on available space. Gaps are against other entities' edges and not against other entities' gaps. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @param size The new gap. + * @see net.miginfocom.layout.ConstraintParser#parseBoundSize(String, boolean, boolean). + */ + public void setGapAfter(BoundSize size) + { + this.gapAfter = size; + } + + boolean hasGapAfter() + { + return gapAfter != null && gapAfter.isUnset() == false; + } + + boolean isGapAfterPush() + { + return gapAfter != null && gapAfter.getGapPush(); + } + + /** Returns the gap before this entitiy. The gap is an empty space and can have a min/preferred/maximum size so that it can shrink and + * grow depending on available space. Gaps are against other entities' edges and not against other entities' gaps. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @return The gap before this entitiy + */ + public BoundSize getGapBefore() + { + return gapBefore; + } + + /** Sets the gap before this entitiy. The gap is an empty space and can have a min/preferred/maximum size so that it can shrink and + * grow depending on available space. Gaps are against other entities' edges and not against other entities' gaps. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @param size The new gap. + * @see net.miginfocom.layout.ConstraintParser#parseBoundSize(String, boolean, boolean). + */ + public void setGapBefore(BoundSize size) + { + this.gapBefore = size; + } + + boolean hasGapBefore() + { + return gapBefore != null && gapBefore.isUnset() == false; + } + + boolean isGapBeforePush() + { + return gapBefore != null && gapBefore.getGapPush(); + } + + /** Returns the min/prerefferd/max size for the entity in the dimension that this object describes. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @return The current size. May be <code>null</code>. + * @see net.miginfocom.layout.ConstraintParser#parseBoundSize(String, boolean, boolean). + */ + public BoundSize getSize() + { + return size; + } + + /** Sets the min/prerefferd/max size for the eintity in the dimension that this object describes. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @param size The new size. May be <code>null</code>. + */ + public void setSize(BoundSize size) + { + this.size = size; + } + + /** Returns the size group that this entitiy should be in for the demension that this object is describing. + * If this constraint is in a size group that is specified here. <code>null</code> means no size group + * and all other values are legal. Comparison with .equals(). Components/columnss/rows in the same size group + * will have the same min/preferred/max size; that of the largest in the group for the first two and the + * smallest for max. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @return The current size group. May be <code>null</code>. + */ + public String getSizeGroup() + { + return sizeGroup; + } + + /** Sets the size group that this entitiy should be in for the demension that this object is describing. + * If this constraint is in a size group that is specified here. <code>null</code> means no size group + * and all other values are legal. Comparison with .equals(). Components/columnss/rows in the same size group + * will have the same min/preferred/max size; that of the largest in the group for the first two and the + * smallest for max. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @param s The new size group. <code>null</code> disables size grouping. + */ + public void setSizeGroup(String s) + { + sizeGroup = s; + } + + // ************** Only applicable on components ! ******************* + + /** Returns the end group that this entitiy should be in for the demension that this object is describing. + * If this constraint is in an end group that is specified here. <code>null</code> means no end group + * and all other values are legal. Comparison with .equals(). Components in the same end group + * will have the same end coordinate. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @return The current end group. <code>null</code> may be returned. + */ + public String getEndGroup() + { + return endGroup; + } + + /** Sets the end group that this entitiy should be in for the demension that this object is describing. + * If this constraint is in an end group that is specified here. <code>null</code> means no end group + * and all other values are legal. Comparison with .equals(). Components in the same end group + * will have the same end coordinate. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @param s The new end group. <code>null</code> disables end grouping. + */ + public void setEndGroup(String s) + { + endGroup = s; + } + + // ************** Not applicable on components below ! ******************* + + /** Returns if the component in the row/column that this constraint should default be grown in the same dimension that + * this constraint represents (width for column and height for a row). + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @return code>true</code> means that components should grow. + */ + public boolean isFill() + { + return fill; + } + + /** Sets if the component in the row/column that this constraint should default be grown in the same dimension that + * this constraint represents (width for column and height for a row). + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @param b <code>true</code> means that components should grow. + */ + public void setFill(boolean b) + { + fill = b; + } + + /** Returns if the row/column should default to flow and not to grid behaviour. This means that the whole row/column + * will be one cell and all components will end up in that cell. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @return <code>true</code> means that the whole row/column should be one cell. + */ + public boolean isNoGrid() + { + return noGrid; + } + + /** Sets if the row/column should default to flow and not to grid behaviour. This means that the whole row/column + * will be one cell and all components will end up in that cell. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @param b <code>true</code> means that the whole row/column should be one cell. + */ + public void setNoGrid(boolean b) + { + this.noGrid = b; + } + + /** Returns the gaps as pixel values. + * @param parent The parent. Used to get the pixel values. + * @param defGap The default gap to use if there is no gap set on this object (i.e. it is null). + * @param refSize The reference size used to get the pixel sizes. + * @param before IF it is the gap before rather than the gap after to return. + * @return The [min,preferred,max] sizes for the specified gap. Uses {@link net.miginfocom.layout.LayoutUtil#NOT_SET} + * for gap sizes that are <code>null</code>. Returns <code>null</code> if there was no gap specified. A new and free to use array. + */ + int[] getRowGaps(ContainerWrapper parent, BoundSize defGap, int refSize, boolean before) + { + BoundSize gap = before ? gapBefore : gapAfter; + if (gap == null || gap.isUnset()) + gap = defGap; + + if (gap == null || gap.isUnset()) + return null; + + int[] ret = new int[3]; + for (int i = LayoutUtil.MIN; i <= LayoutUtil.MAX; i++) { + UnitValue uv = gap.getSize(i); + ret[i] = uv != null ? uv.getPixels(refSize, parent, null) : LayoutUtil.NOT_SET; + } + return ret; + } + + /** Returns the gaps as pixel values. + * @param parent The parent. Used to get the pixel values. + * @param comp The component that the gap is for. If not for a component it is <code>null</code>. + * @param adjGap The gap that the adjacent component, if any, has towards <code>comp</code>. + * @param adjacentComp The adjacent component if any. May be <code>null</code>. + * @param refSize The reference size used to get the pixel sizes. + * @param adjacentSide Whan side the <code>adjacentComp</code> is on. 0 = top, 1 = left, 2 = bottom, 3 = right. + * @param tag The tag string that the component might be tagged with in the component constraints. May be <code>null</code>. + * @param isLTR If it is left-to-right. + * @return The [min,preferred,max] sizes for the specified gap. Uses {@link net.miginfocom.layout.LayoutUtil#NOT_SET} + * for gap sizes that are <code>null</code>. Returns <code>null</code> if there was no gap specified. A new and free to use array. + */ + int[] getComponentGaps(ContainerWrapper parent, ComponentWrapper comp, BoundSize adjGap, ComponentWrapper adjacentComp, String tag, int refSize, int adjacentSide, boolean isLTR) + { + BoundSize gap = adjacentSide < 2 ? gapBefore : gapAfter; + + boolean hasGap = gap != null && gap.getGapPush(); + if ((gap == null || gap.isUnset()) && (adjGap == null || adjGap.isUnset()) && comp != null) + gap = PlatformDefaults.getDefaultComponentGap(comp, adjacentComp, adjacentSide + 1, tag, isLTR); + + if (gap == null) + return hasGap ? new int[] {0, 0, LayoutUtil.NOT_SET} : null; + + int[] ret = new int[3]; + for (int i = LayoutUtil.MIN; i <= LayoutUtil.MAX; i++) { + UnitValue uv = gap.getSize(i); + ret[i] = uv != null ? uv.getPixels(refSize, parent, null) : LayoutUtil.NOT_SET; + } + return ret; + } + + // ************************************************ + // Persistence Delegate and Serializable combined. + // ************************************************ + + private Object readResolve() throws ObjectStreamException + { + return LayoutUtil.getSerializedObject(this); + } + + public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException + { + LayoutUtil.setSerializedObject(this, LayoutUtil.readAsXML(in)); + } + + public void writeExternal(ObjectOutput out) throws IOException + { + if (getClass() == DimConstraint.class) + LayoutUtil.writeAsXML(out, this); + } +} diff --git a/prototypes/miglayout/net/miginfocom/layout/Grid.java b/prototypes/miglayout/net/miginfocom/layout/Grid.java index c45ce398..3c19254c 100644 --- a/prototypes/miglayout/net/miginfocom/layout/Grid.java +++ b/prototypes/miglayout/net/miginfocom/layout/Grid.java @@ -1,2245 +1,2245 @@ -package net.miginfocom.layout;
-
-
-import java.util.*;
-/*
- * License (BSD):
- * ==============
- *
- * Copyright (c) 2004, Mikael Grev, MiG InfoCom AB. (miglayout (at) miginfocom (dot) com)
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification,
- * are permitted provided that the following conditions are met:
- * Redistributions of source code must retain the above copyright notice, this list
- * of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above copyright notice, this
- * list of conditions and the following disclaimer in the documentation and/or other
- * materials provided with the distribution.
- * Neither the name of the MiG InfoCom AB nor the names of its contributors may be
- * used to endorse or promote products derived from this software without specific
- * prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
- * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
- * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
- * OF SUCH DAMAGE.
- *
- * @version 1.0
- * @author Mikael Grev, MiG InfoCom AB
- * Date: 2006-sep-08
- */
-
-/** Holds components in a grid. Does most of the logic behind the layout manager.
- */
-public final class Grid
-{
- public static final boolean TEST_GAPS = true;
-
- private static final Float[] GROW_100 = new Float[] {ResizeConstraint.WEIGHT_100};
-
- private static final DimConstraint DOCK_DIM_CONSTRAINT = new DimConstraint();
- static {
- DOCK_DIM_CONSTRAINT.setGrowPriority(0);
- }
-
- /** This is the maximum grid position for "normal" components. Docking components use the space out to
- * <code>MAX_DOCK_GRID</code> and below 0.
- */
- private static final int MAX_GRID = 30000;
-
- /** Docking components will use the grid coordinates <code>-MAX_DOCK_GRID -> 0</code> and <code>MAX_GRID -> MAX_DOCK_GRID</code>.
- */
- private static final int MAX_DOCK_GRID = 32767;
-
- /** A constraint used for gaps.
- */
- private static final ResizeConstraint GAP_RC_CONST = new ResizeConstraint(200, ResizeConstraint.WEIGHT_100, 50, null);
- private static final ResizeConstraint GAP_RC_CONST_PUSH = new ResizeConstraint(200, ResizeConstraint.WEIGHT_100, 50, ResizeConstraint.WEIGHT_100);
-
- /** The constraints. Never <code>null</code>.
- */
- private final LC lc;
-
- /** The parent that is layout out and this grid is done for. Never <code>null</code>.
- */
- private final ContainerWrapper container;
-
- /** An x, y array implemented as a sparse array to accomodate for any grid size without wasting memory (or rather 15 bit (0-MAX_GRID * 0-MAX_GRID).
- */
- private final LinkedHashMap<Integer, Cell> grid = new LinkedHashMap<Integer, Cell>(); // [(y << 16) + x] -> Cell. null key for absolute positioned compwraps
-
- private HashMap<Integer, BoundSize> wrapGapMap = null; // Row or Column index depending in the dimension that "raps". Normally row indexes but may be column indexes if "flowy". 0 means before first row/col.
-
- /** The size of the grid. Row count and column count.
- */
- private final TreeSet<Integer> rowIndexes = new TreeSet<Integer>(), colIndexes = new TreeSet<Integer>();
-
- /** The row and column specifications.
- */
- private final AC rowConstr, colConstr;
-
- /** The in the constructor calculated min/pref/max sizes of the rows and columns.
- */
- private FlowSizeSpec colFlowSpecs = null, rowFlowSpecs = null;
-
- /** Components that are connectione in one dimension (such as baseline alignment for instance) are grouped together and stored here.
- * One for each row/column.
- */
- private ArrayList<LinkedDimGroup>[] colGroupLists, rowGroupLists; //[(start)row/col number]
-
- /** The in the constructor calculated min/pref/max size of the whole grid.
- */
- private int[] width = null, height = null;
-
- /** If debug is on contains the bounds for things to paint when calling {@link ContainerWrapper#paintDebugCell(int, int, int, int)}
- */
- private ArrayList<int[]> debugRects = null; // [x, y, width, height]
-
- /** If any of the absolute coordinates for component bounds has links the name of the target is in this Set.
- * Since it requires some memory and computations this is checked at the creation so that
- * the link information is only created if needed later.
- * <p>
- * The boolean is true for groups id:s and null for normal id:s.
- */
- private HashMap<String, Boolean> linkTargetIDs = null;
-
- private final int dockOffY, dockOffX;
-
- private final Float[] growXs, growYs;
-
- private final ArrayList<LayoutCallback> callbackList;
-
- /** Constructor.
- * @param container The container that will be laid out.
- * @param lc The form flow constraints.
- * @param rowConstr The rows specifications. If more cell rows are required, the last element will be used for when there is no corresponding element in this array.
- * @param colConstr The columns specifications. If more cell rows are required, the last element will be used for when there is no corresponding element in this array.
- * @param fcMap The map containing the parsed constraints for each child component of <code>parent</code>. Will not be alterted.
- * @param callbackList A list of callbacks or <code>null</code> if none. Will not be alterted.
- */
- public Grid(ContainerWrapper container, LC lc, AC rowConstr, AC colConstr, Map<ComponentWrapper, CC> fcMap, ArrayList<LayoutCallback> callbackList)
- {
- this.lc = lc;
- this.rowConstr = rowConstr;
- this.colConstr = colConstr;
- this.container = container;
- this.callbackList = callbackList;
-
- int wrap = lc.getWrapAfter() != 0 ? lc.getWrapAfter() : (lc.isFlowX() ? colConstr : rowConstr).getConstaints().length;
-
- final ComponentWrapper[] comps = container.getComponents();
-
- boolean hasTagged = false; // So we do not have to sort if it will not do any good
- boolean hasPushX = false, hasPushY = false;
- final int[] p = new int[2];
- final ArrayList<int[]> spannedRects = new ArrayList<int[]>(2);
-
- final DimConstraint[] specs = (lc.isFlowX() ? rowConstr : colConstr).getConstaints();
-
- int sizeGroupsX = 0, sizeGroupsY = 0;
- int[] dockInsets = null; // top, left, bottom, right insets for docks.
-
- LinkHandler.clearTemporaryBounds(container.getLayout());
-
- for (int i = 0; i < comps.length;) {
- ComponentWrapper comp = comps[i];
- CC rootCc = fcMap.get(comp);
-
- int hideMode = comp.isVisible() ? -1 : rootCc.getHideMode() != -1 ? rootCc.getHideMode() : lc.getHideMode();
-
- if (rootCc == null || hideMode == 3) { // To work with situations where there are components that does not have a layout manager, or not this one.
- if (rootCc != null)
- setLinkedBounds(comp, rootCc, comp.getX(), comp.getY(), comp.getWidth(), comp.getHeight(), rootCc.isExternal());
- i++;
- continue; // The "external" component should not be handled further.
- }
-
- if (rootCc.getHorizontal().getSizeGroup() != null)
- sizeGroupsX++;
- if (rootCc.getVertical().getSizeGroup() != null)
- sizeGroupsY++;
-
- // Special treatment of absolute positioned components.
- UnitValue[] pos = getPos(comp, rootCc);
- BoundSize[] cbSz = getCallbackSize(comp, rootCc);
- if (pos != null || rootCc.isExternal()) {
-
- // Check if link information should be saved later.
- if (pos != null) {
- for (int l = 0; l < pos.length; l++) {
- UnitValue u = pos[l];
- if (u != null && u.isLinkedDeep())
- addLinkTargetIDs(u);
- }
- }
-
- CompWrap cw = new CompWrap(comp, rootCc, hideMode, pos, cbSz);
- Cell cell = grid.get(null);
- if (cell == null) {
- grid.put(null, new Cell(cw));
- } else {
- cell.compWraps.add(cw);
- }
-
- if (rootCc.isBoundsInGrid() == false || rootCc.isExternal()) {
- setLinkedBounds(comp, rootCc, comp.getX(), comp.getY(), comp.getWidth(), comp.getHeight(), rootCc.isExternal());
- i++;
- continue;
- }
- }
-
- if (rootCc.getDockSide() != -1) {
- if (dockInsets == null)
- dockInsets = new int[] {-MAX_DOCK_GRID, -MAX_DOCK_GRID, MAX_DOCK_GRID, MAX_DOCK_GRID};
-
- addDockingCell(dockInsets, rootCc.getDockSide(), new CompWrap(comp, rootCc, hideMode, pos, cbSz));
- i++;
- continue;
- }
-
- Boolean cellFlowX = rootCc.getFlowX();
- Cell cell = null;
-
- if (rootCc.isNewline())
- wrap(p, rootCc.getNewlineGapSize(), true);
-
- increase(p, rootCc.getSkip()); // Probably 0 advance...
-
- boolean rowNoGrid = lc.isNoGrid() || ((DimConstraint) LayoutUtil.getIndexSafe(specs, lc.isFlowX() ? p[1] : p[0])).isNoGrid();
-
- // Move to a free y, x if no absolute grid specified
- int cx = rootCc.getCellX();
- int cy = rootCc.getCellY();
- if ((cx < 0 || cy < 0) && rowNoGrid == false) {
- while (isCellFree(p[1], p[0], spannedRects) == false) {
- if (Math.abs(increase(p, 1)) >= wrap)
- wrap(p, null, true);
- }
- } else {
- if (cx >= 0 && cy >= 0) {
- if (cy >= 0) {
- p[0] = cx;
- p[1] = cy;
- } else { // Only one coordinate is specified. Use the current row (flowx) or column (flowy) to fill in.
- if (lc.isFlowX()) {
- p[0] = cx;
- } else {
- p[1] = cx;
- }
- }
- }
- cell = getCell(p[1], p[0]); // Might be null
- }
-
- // If cell is not created yet, create it and set it.
- if (cell == null) {
- int spanx = Math.min(rowNoGrid && lc.isFlowX() ? LayoutUtil.INF : rootCc.getSpanX(), MAX_GRID - p[0]);
- int spany = Math.min(rowNoGrid && !lc.isFlowX() ? LayoutUtil.INF : rootCc.getSpanY(), MAX_GRID - p[1]);
-
- cell = new Cell(spanx, spany, cellFlowX != null ? cellFlowX.booleanValue() : lc.isFlowX());
-
- setCell(p[1], p[0], cell);
-
- // Add a rectangle so we can know that spanned cells occupy more space.
- if (spanx > 1 || spany > 1)
- spannedRects.add(new int[] {p[0], p[1], spanx, spany});
- }
-
- // Add the one, or all, components that split the grid position to the same Cell.
- boolean forceWrap = false;
- BoundSize wrapGap = null;
- int splitLeft = rowNoGrid ? LayoutUtil.INF : rootCc.getSplit() - 1;
- boolean splitExit = false;
- for (; splitLeft >= 0 && forceWrap == false && i < comps.length; splitLeft--) {
- ComponentWrapper compAdd = comps[i];
- CC cc = fcMap.get(compAdd); // Can not be null.
-
- hideMode = compAdd.isVisible() ? -1 : cc.getHideMode() != -1 ? cc.getHideMode() : lc.getHideMode();
-
- if (cc == null || cc.isExternal() || hideMode == 3) {
- i++;
- continue; // To work with situations where there are components that does not have a layout manager, or not this one.
- }
-
- hasPushX |= (cc.getPushX() != null);
- hasPushY |= (cc.getPushY() != null);
-
- if (cc != rootCc) { // If not first in a cell
- if (cc.isNewline() || cc.isBoundsInGrid() == false)
- break;
-
- if (splitLeft > 0 && cc.getSkip() > 0) {
- splitExit = true;
- break;
- }
-
- pos = getPos(compAdd, cc);
- cbSz = getCallbackSize(compAdd, cc);
- }
-
- CompWrap cw = new CompWrap(compAdd, cc, hideMode, pos, cbSz);
- cell.compWraps.add(cw);
- cell.hasTagged |= cc.getTag() != null;
- hasTagged |= cell.hasTagged;
-
- if (cc != rootCc) {
- if (cc.getHorizontal().getSizeGroup() != null)
- sizeGroupsX++;
- if (cc.getVertical().getSizeGroup() != null)
- sizeGroupsY++;
- }
-
- int flowSpan = lc.isFlowX() ? rootCc.getSpanX() : rootCc.getSpanY();
- forceWrap = (cc.isWrap() || (flowSpan == LayoutUtil.INF && splitLeft == 0));
- wrapGap = cc.getWrapGapSize();
- i++;
- }
-
- if (forceWrap) {
- wrap(p, wrapGap, true);
- } else if (rowNoGrid == false) {
- int span = lc.isFlowX() ? cell.spanx : cell.spany;
- if (Math.abs((lc.isFlowX() ? p[0] : p[1])) + span >= wrap) {
- wrap(p, null, true);
- } else {
- int adv = lc.isFlowX() ? cell.spanx : cell.spany;
- if (splitExit)
- adv--;
- increase(p, adv);
- }
- }
- }
-
- // If there were size groups, calculate the largest values in the groups (for min/pref/max) and enforce them on the rest in the group.
- if (sizeGroupsX > 0 || sizeGroupsY > 0) {
- HashMap<String, int[]> sizeGroupMapX = sizeGroupsX > 0 ? new HashMap<String, int[]>(sizeGroupsX) : null;
- HashMap<String, int[]> sizeGroupMapY = sizeGroupsY > 0 ? new HashMap<String, int[]>(sizeGroupsY) : null;
- ArrayList<CompWrap> sizeGroupCWs = new ArrayList<CompWrap>(Math.max(sizeGroupsX, sizeGroupsY));
-
- for (Iterator<Cell> it = grid.values().iterator(); it.hasNext();) {
- Cell cell = it.next();
- for (int i = 0; i < cell.compWraps.size(); i++) {
- CompWrap cw = cell.compWraps.get(i);
-
- if (cw.cc.getHorizontal().getSizeGroup() != null || cw.cc.getVertical().getSizeGroup() != null) {
- addToSizeGroup(sizeGroupMapX, cw.cc.getHorizontal().getSizeGroup(), cw.horSizes);
- addToSizeGroup(sizeGroupMapY, cw.cc.getVertical().getSizeGroup(), cw.verSizes);
- sizeGroupCWs.add(cw);
- }
- }
- }
-
- // Set/equalize the sizeGroups to same the values.
- if (sizeGroupCWs != null) {
- for (int i = 0; i < sizeGroupCWs.size(); i++) {
- CompWrap cw = sizeGroupCWs.get(i);
- if (sizeGroupMapX != null)
- cw.setSizes(sizeGroupMapX.get(cw.cc.getHorizontal().getSizeGroup()), true); // Target method handles null sizes
- if (sizeGroupMapY != null)
- cw.setSizes(sizeGroupMapY.get(cw.cc.getVertical().getSizeGroup()), false); // Target method handles null sizes
- }
- }
- }
-
- if (hasTagged)
- sortCellsByPlatform(grid.values(), container);
-
- // Calculate gaps now that the cells are filled and we know all adjacent components.
- boolean ltr = LayoutUtil.isLeftToRight(lc, container);
- for (Iterator<Cell> it = grid.values().iterator(); it.hasNext();) {
- Cell cell = it.next();
- ArrayList<CompWrap> cws = cell.compWraps;
-
- for (int i = 0, lastI = cws.size() - 1; i <= lastI; i++) {
- CompWrap cw = cws.get(i);
- ComponentWrapper cwBef = i > 0 ? cws.get(i - 1).comp : null;
- ComponentWrapper cwAft = i < lastI ? cws.get(i + 1).comp : null;
-
- String tag = fcMap.get(cw.comp).getTag();
- CC ccBef = cwBef != null ? fcMap.get(cwBef) : null;
- CC ccAft = cwAft != null ? fcMap.get(cwAft) : null;
-
- cw.calcGaps(cwBef, ccBef, cwAft, ccAft, tag, cell.flowx, ltr);
- }
- }
-
- dockOffX = getDockInsets(colIndexes);
- dockOffY = getDockInsets(rowIndexes);
-
- // Add synthetic indexes for empty rows and columns so they can get a size
- for (int i = 0, iSz = rowConstr.getCount(); i < iSz; i++)
- rowIndexes.add(new Integer(i));
- for (int i = 0, iSz = colConstr.getCount(); i < iSz; i++)
- colIndexes.add(new Integer(i));
-
- colGroupLists = divideIntoLinkedGroups(false);
- rowGroupLists = divideIntoLinkedGroups(true);
-
- growXs = getDefaultGrowWeights(hasPushX, false);
- growYs = getDefaultGrowWeights(hasPushY, true);
-
- }
-
- /** If the container (parent) that this grid is laying out has changed its bounds, call this method to
- * clear any cached values.
- */
- public void invalidateContainerSize()
- {
- colFlowSpecs = null;
- }
-
- /** Does the actual layout. Uses many values calculated in the constructor.
- * @param bounds The bounds to layout against. Normally that of the parent. [x, y, width, height].
- * @param alignX The alignment for the x-axis.
- * @param alignY The alignment for the y-axis.
- * @param debug If debug information should be saved in {@link #debugRects}.
- * @param checkPrefChange If a check should be done to see if the setting of any new bounds changes the preferred size
- * of a component. This is normally only turned on for SWT as SWT has a notion of width vs height calculation.
- * @return If the layout has probably change the preferred size and there is need for a new layout (normally only SWT).
- */
- public boolean layout(int[] bounds, UnitValue alignX, UnitValue alignY, boolean debug, boolean checkPrefChange)
- {
- if (debug)
- debugRects = new ArrayList<int[]>();
-
- checkSizeCalcs();
-
- resetLinkValues(true);
-
- layoutInOneDim(bounds[2], alignX, false, growXs);
- layoutInOneDim(bounds[3], alignY, true, growYs);
-
- HashMap<String, Integer> endGrpXMap = null, endGrpYMap = null;
- int compCount = container.getComponentCount();
-
- // Transfer the calculated bound from the ComponentWrappers to the actual Components.
- boolean layoutAgain = false;
- if (compCount > 0) {
- for (int j = 0; j < (linkTargetIDs != null ? 2 : 1); j++) { // First do the calculations (maybe more than once) then set the bounds when done
- boolean doAgain;
- int count = 0;
- do {
- doAgain = false;
- for (Iterator<Cell> it = grid.values().iterator(); it.hasNext();) {
- ArrayList<CompWrap> compWraps = it.next().compWraps;
- for (int i = 0, iSz = compWraps.size(); i < iSz; i++) {
- CompWrap cw = compWraps.get(i);
-
- if (j == 0) {
- doAgain |= doAbsoluteCorrections(cw, bounds);
- if (doAgain == false) { // If we are going to do this again, do not bother this time around
- if (cw.cc.getHorizontal().getEndGroup() != null)
- endGrpXMap = addToEndGroup(endGrpXMap, cw.cc.getHorizontal().getEndGroup(), cw.x + cw.w);
- if (cw.cc.getVertical().getEndGroup() != null)
- endGrpYMap = addToEndGroup(endGrpYMap, cw.cc.getVertical().getEndGroup(), cw.y + cw.h);
- }
- }
-
- if (linkTargetIDs == null || j == 1) {
- if (cw.cc.getHorizontal().getEndGroup() != null)
- cw.w = endGrpXMap.get(cw.cc.getHorizontal().getEndGroup()).intValue() - cw.x;
- if (cw.cc.getVertical().getEndGroup() != null)
- cw.h = endGrpYMap.get(cw.cc.getVertical().getEndGroup()).intValue() - cw.y;
-
- cw.x += bounds[0];
- cw.y += bounds[1];
- layoutAgain = cw.transferBounds(checkPrefChange && !layoutAgain);
-
- if (callbackList != null) {
- for (int cb = 0; cb < callbackList.size(); cb++)
- callbackList.get(cb).correctBounds(cw.comp);
- }
- }
- }
- }
- clearGroupLinkBounds();
- if (++count > ((compCount << 3) + 10)) {
- System.err.println("Unstable Cyclic Dependency in absolute-linked values!");
- break;
- }
-
- } while (doAgain);
- }
- }
-
- // Add debug shapes for the "cells". Use the CompWraps as base for inding the cells.
- if (debug) {
- Collection<Cell> cwColl = grid.values();
- for (Iterator<Cell> it = cwColl.iterator(); it.hasNext();) {
- ArrayList<CompWrap> compWraps = it.next().compWraps;
- for (int i = 0, iSz = compWraps.size(); i < iSz; i++) {
- CompWrap cw = compWraps.get(i);
- LinkedDimGroup hGrp = getGroupContaining(colGroupLists, cw);
- LinkedDimGroup vGrp = getGroupContaining(rowGroupLists, cw);
-
- if (hGrp != null && vGrp != null)
- debugRects.add(new int[] {hGrp.lStart + bounds[0] - (hGrp.fromEnd ? hGrp.lSize : 0), vGrp.lStart + bounds[1] - (vGrp.fromEnd ? vGrp.lSize : 0), hGrp.lSize, vGrp.lSize});
- }
- }
- }
- return layoutAgain;
- }
-
- public void paintDebug()
- {
- if (debugRects != null) {
- container.paintDebugOutline();
-
- ArrayList<int[]> painted = new ArrayList<int[]>();
- for (int i = 0, iSz = debugRects.size(); i < iSz; i++) {
- int[] r = debugRects.get(i);
- if (painted.contains(r) == false) {
- container.paintDebugCell(r[0], r[1], r[2], r[3]);
- painted.add(r);
- }
- }
-
- for (Iterator<Cell> it = grid.values().iterator(); it.hasNext();) {
- ArrayList<CompWrap> compWraps = it.next().compWraps;
- for (int i = 0, iSz = compWraps.size(); i < iSz; i++)
- compWraps.get(i).comp.paintDebugOutline();
- }
- }
- }
-
- public final int[] getWidth()
- {
- checkSizeCalcs();
- return width;
- }
-
- public final int[] getHeight()
- {
- checkSizeCalcs();
- return height;
- }
-
- private void checkSizeCalcs()
- {
- if (colFlowSpecs == null) {
- colFlowSpecs = calcRowsOrColsSizes(colGroupLists, growXs, container.getWidth(), true);
- rowFlowSpecs = calcRowsOrColsSizes(rowGroupLists, growYs, container.getHeight(), false);
-
- width = getMinPrefMaxSumSize(colFlowSpecs.sizes);
- height = getMinPrefMaxSumSize(rowFlowSpecs.sizes);
-
- resetLinkValues(false);
-
- adjustSizeForAbsolute(width, true);
- adjustSizeForAbsolute(height, false);
- }
- }
-
- private final UnitValue[] getPos(ComponentWrapper cw, CC cc)
- {
- UnitValue[] cbPos = null;
- if (callbackList != null) {
- for (int i = 0; i < callbackList.size() && cbPos == null; i++)
- cbPos = callbackList.get(i).getPosition(cw); // NOT a copy!
- }
-
- // If one is null, return the other (which many also be null)
- UnitValue[] ccPos = cc.getPos(); // A copy!!
- if (cbPos == null || ccPos == null)
- return cbPos != null ? cbPos : ccPos;
-
- // Merge
- for (int i = 0; i < 4; i++) {
- UnitValue cbUv = cbPos[i];
- if (cbUv != null)
- ccPos[i] = cbUv;
- }
-
- return ccPos;
- }
- private final BoundSize[] getCallbackSize(ComponentWrapper cw, CC cc)
- {
- if (callbackList != null) {
- for (int i = 0; i < callbackList.size(); i++) {
- BoundSize[] bs = callbackList.get(i).getSize(cw); // NOT a copy!
- if (bs != null)
- return bs;
- }
- }
- return null;
- }
-
- private final int getDockInsets(TreeSet<Integer> set)
- {
- int c = 0;
- for (Iterator<Integer> it = set.iterator(); it.hasNext();) {
- if (it.next().intValue() < -MAX_GRID) {
- c++;
- } else {
- break; // Since they are sorted we can break
- }
- }
- return c;
- }
-
- /**
- * @param cw Never <code>null</code>.
- * @param fc Never <code>null</code>.
- * @param external The bounds should be stored even if they are not in {@link #linkTargetIDs}.
- * @return IF a change has been done.
- */
- private boolean setLinkedBounds(ComponentWrapper cw, CC fc, int x, int y, int w, int h, boolean external)
- {
- String id = fc.getId() != null ? fc.getId() : cw.getLinkId();
- if (id == null)
- return false;
-
- String gid = null;
- int grIx = id.indexOf('.');
- if (grIx != -1 ) {
- gid = id.substring(0, grIx);
- id = id.substring(grIx + 1);
- }
-
- Object lay = container.getLayout();
- boolean changed = false;
- if (external || (linkTargetIDs != null && linkTargetIDs.containsKey(id)))
- changed = LinkHandler.setBounds(lay, id, x, y, w, h, !external, false);
-
- if (gid != null && (external || (linkTargetIDs != null && linkTargetIDs.containsKey(gid)))) {
- if (linkTargetIDs == null)
- linkTargetIDs = new HashMap<String, Boolean>(4);
-
- linkTargetIDs.put(gid, Boolean.TRUE);
- changed |= LinkHandler.setBounds(lay, gid, x, y, w, h, !external, true);
- }
-
- return changed;
- }
-
- private void addLinkTargetIDs(UnitValue uv)
- {
- if (uv.isLinked()) {
- if (linkTargetIDs == null)
- linkTargetIDs = new HashMap<String, Boolean>(4);
-
- linkTargetIDs.put(uv.getLinkTargetId(), null);
- } else {
- for (int i = uv.getSubUnitCount() - 1; i >= 0; i--) {
- UnitValue subUv = uv.getSubUnitValue(i);
- if (subUv.isLinkedDeep())
- addLinkTargetIDs(subUv);
- }
- }
- }
-
- /** Go to next cell.
- * @param p The point to increase
- * @param cnt How many cells to advance.
- * @return The new value in the "incresing" dimension.
- */
- private final int increase(int[] p, int cnt)
- {
- return lc.isFlowX() ? (p[0] += cnt) : (p[1] += cnt);
- }
-
- /** Wraps to the next row or column depending on if horizontal flow or vertical flow is used.
- * @param p The point to wrap and thus set either x or y to 0 and increase the other one.
- * @param gapSize The gaps size specified in a "wrap XXX" or "newline XXX" or <code>null</code> if none.
- * @param isWrap If gapSize is from a "wrap" (true) or "newline" (false).
- */
- private final void wrap(int[] p, BoundSize gapSize, boolean isWrap)
- {
- boolean flowx = lc.isFlowX();
- p[0] = flowx ? 0 : p[0] + 1;
- p[1] = flowx ? p[1] + 1 : 0;
-
- if (gapSize != null) {
- if (wrapGapMap == null)
- wrapGapMap = new HashMap<Integer, BoundSize>(8);
- int ix = p[flowx ? 1 : 0];
- if (isWrap == false)
- ix--; // newline. Use index before increment.
- wrapGapMap.put(new Integer(ix), gapSize);
-
- // add the row/column so that the gap in the last row/col will not be removed.
- if (flowx) {
- rowIndexes.add(new Integer(p[1]));
- } else {
- colIndexes.add(new Integer(p[0]));
- }
- }
- }
-
- /** Sort components (normally buttons in a button bar) so they appear in the correct order.
- * @param cells The cells to sort.
- * @param parent The parent.
- */
- private static void sortCellsByPlatform(Collection<Cell> cells, ContainerWrapper parent)
- {
- String order = PlatformDefaults.getButtonOrder();
- String orderLo = order.toLowerCase();
-
- int unrelSize = PlatformDefaults.convertToPixels(1, "u", true, 0, parent, null);
-
- if (unrelSize == UnitConverter.UNABLE)
- throw new IllegalArgumentException("'unrelated' not recognized by PlatformDefaults!");
-
- int[] gapUnrel = new int[] {unrelSize, unrelSize, LayoutUtil.NOT_SET};
- int[] flGap = new int[] {0, 0, LayoutUtil.NOT_SET};
-
- for (Iterator<Cell> it = cells.iterator(); it.hasNext();) {
- Cell cell = it.next();
- if (cell.hasTagged == false)
- continue;
-
- CompWrap prevCW = null;
- boolean nextUnrel = false;
- boolean nextPush = false;
- ArrayList<CompWrap> sortedList = new ArrayList<CompWrap>(cell.compWraps.size());
-
- for (int i = 0, iSz = orderLo.length(); i < iSz; i++) {
- char c = orderLo.charAt(i);
- if (c == '+' || c == '_') {
- nextUnrel = true;
- if (c == '+')
- nextPush = true;
- } else {
- String tag = PlatformDefaults.getTagForChar(c);
- if (tag != null) {
- for (int j = 0, jSz = cell.compWraps.size(); j < jSz; j++) {
- CompWrap cw = cell.compWraps.get(j);
- if (tag.equals(cw.cc.getTag())) {
- if (Character.isUpperCase(order.charAt(i))) {
- int min = PlatformDefaults.getMinimumButtonWidth().getPixels(0, parent, cw.comp);
- if (min > cw.horSizes[LayoutUtil.MIN])
- cw.horSizes[LayoutUtil.MIN] = min;
-
- correctMinMax(cw.horSizes);
- }
-
- sortedList.add(cw);
-
- if (nextUnrel) {
- (prevCW != null ? prevCW : cw).mergeGapSizes(gapUnrel, cell.flowx, prevCW == null);
- if (nextPush) {
- cw.forcedPushGaps = 1;
- nextUnrel = false;
- nextPush = false;
- }
- }
-
- // "unknown" components will always get an Unrelated gap.
- if (c == 'u')
- nextUnrel = true;
- prevCW = cw;
- }
- }
- }
- }
- }
-
- // If we have a gap that was supposed to push but no more components was found to but the "gap before" then compensate.
- if (sortedList.size() > 0) {
- CompWrap cw = sortedList.get(sortedList.size() - 1);
- if (nextUnrel) {
- cw.mergeGapSizes(gapUnrel, cell.flowx, false);
- if (nextPush)
- cw.forcedPushGaps |= 2;
- }
-
- // Remove first and last gap if not set explicitly.
- if (cw.cc.getHorizontal().getGapAfter() == null)
- cw.setGaps(flGap, 3);
-
- cw = sortedList.get(0);
- if (cw.cc.getHorizontal().getGapBefore() == null)
- cw.setGaps(flGap, 1);
- }
-
- // Exchange the unsorted CompWraps for the sorted one.
- if (cell.compWraps.size() == sortedList.size()) {
- cell.compWraps.clear();
- } else {
- cell.compWraps.removeAll(sortedList);
- }
- cell.compWraps.addAll(sortedList);
- }
- }
-
- private Float[] getDefaultGrowWeights(boolean hasPush, boolean isRows)
- {
- if (hasPush == false && (isRows ? lc.isFillY() : lc.isFillX()) == false)
- return null;
-
- ArrayList<LinkedDimGroup>[] groupLists = isRows ? rowGroupLists : colGroupLists;
-
- Float[] gwArr = GROW_100; // Only create specific if any of the components have grow.
- for (int i = 0, ix = 1; i < groupLists.length; i++, ix += 2) {
- ArrayList<LinkedDimGroup> grps = groupLists[i];
- Float rowGw = null;
- for (int j = 0; j < grps.size(); j++) {
- LinkedDimGroup grp = grps.get(j);
-
- for (int c = 0; c < grp._compWraps.size(); c++) {
- CompWrap cw = grp._compWraps.get(c);
- Float gw = hasPush ? (isRows ? cw.cc.getPushY() : cw.cc.getPushX()) : (isRows ? cw.cc.getVertical() : cw.cc.getHorizontal()).getGrow();
- if (rowGw == null || (gw != null && gw.floatValue() > rowGw.floatValue()))
- rowGw = gw;
- }
- }
-
- if (rowGw != null) {
- if (gwArr == GROW_100)
- gwArr = new Float[(groupLists.length << 1) + 1];
- gwArr[ix] = rowGw;
- }
- }
-
- return gwArr;
- }
-
- private void clearGroupLinkBounds()
- {
- if (linkTargetIDs == null)
- return;
-
- for (Iterator<Map.Entry<String,Boolean>> it = linkTargetIDs.entrySet().iterator(); it.hasNext();) {
- Map.Entry<String, Boolean> o = it.next();
- if (o.getValue() == Boolean.TRUE)
- LinkHandler.clearBounds(container.getLayout(), o.getKey());
- }
- }
-
- private void resetLinkValues(boolean parentSize)
- {
- Object lay = container.getLayout();
- LinkHandler.clearTemporaryBounds(lay);
-
- boolean defIns = !hasDocks();
-
- int parW = parentSize ? container.getWidth() : 0;
- int parH = parentSize ? container.getHeight() : 0;
- int insX = LayoutUtil.getInsets(lc, 0, defIns).getPixels(0, container, null);
- int insY = LayoutUtil.getInsets(lc, 1, defIns).getPixels(0, container, null);
- int insW = parW - insX - LayoutUtil.getInsets(lc, 2, defIns).getPixels(0, container, null);
- int insH = parH - insY - LayoutUtil.getInsets(lc, 3, defIns).getPixels(0, container, null);
-
- LinkHandler.setBounds(lay, "visual", insX, insY, insW, insH, true, false);
- LinkHandler.setBounds(lay, "container", 0, 0, parW, parH, true, false);
- }
-
- /** Returns the {@link net.miginfocom.layout.Grid.LinkedDimGroup} that has the {@link net.miginfocom.layout.Grid.CompWrap}
- * <code>cw</code>.
- * @param groupLists The lists to search in.
- * @param cw The component wrap to find.
- * @return The linked group or <code>null</code> if none had the component wrap.
- */
- private static LinkedDimGroup getGroupContaining(ArrayList<LinkedDimGroup>[] groupLists, CompWrap cw)
- {
- for (int i = 0; i < groupLists.length; i++) {
- ArrayList<LinkedDimGroup> groups = groupLists[i];
- for (int j = 0, jSz = groups.size(); j < jSz; j++) {
- ArrayList<CompWrap> cwList = groups.get(j)._compWraps;
- for (int k = 0, kSz = cwList.size(); k < kSz; k++) {
- if (cwList.get(k) == cw)
- return groups.get(j);
- }
- }
- }
- return null;
- }
-
- private boolean doAbsoluteCorrections(CompWrap cw, int[] bounds)
- {
- boolean changed = false;
-
- int[] stSz = getAbsoluteDimBounds(cw, bounds[2], true);
- if (stSz != null)
- cw.setDimBounds(stSz[0], stSz[1], true);
-
- stSz = getAbsoluteDimBounds(cw, bounds[3], false);
- if (stSz != null)
- cw.setDimBounds(stSz[0], stSz[1], false);
-
- // If there is a link id, store the new bounds.
- if (linkTargetIDs != null)
- changed = setLinkedBounds(cw.comp, cw.cc, cw.x, cw.y, cw.w, cw.h, false);
-
- return changed;
- }
-
- private void adjustSizeForAbsolute(int[] curSizes, boolean isHor)
- {
- Cell absCell = grid.get(null);
- if (absCell == null || absCell.compWraps.size() == 0)
- return;
-
- ArrayList<CompWrap> cws = absCell.compWraps;
-
- int maxEnd = 0;
- for (int j = 0, cwSz = absCell.compWraps.size(); j < cwSz + 3; j++) { // "Do Again" max absCell.compWraps.size() + 3 times.
- boolean doAgain = false;
- for (int i = 0; i < cwSz; i++) {
- CompWrap cw = cws.get(i);
- int[] stSz = getAbsoluteDimBounds(cw, 0, isHor);
- int end = stSz[0] + stSz[1];
- if (maxEnd < end)
- maxEnd = end;
-
- // If there is a link id, store the new bounds.
- if (linkTargetIDs != null)
- doAgain |= setLinkedBounds(cw.comp, cw.cc, stSz[0], stSz[0], stSz[1], stSz[1], false);
- }
- if (doAgain == false)
- break;
-
- // We need to check this again since the coords may be smaller this round.
- maxEnd = 0;
- clearGroupLinkBounds();
- }
-
- maxEnd += LayoutUtil.getInsets(lc, isHor ? 3 : 2, !hasDocks()).getPixels(0, container, null);
-
- if (curSizes[LayoutUtil.MIN] < maxEnd)
- curSizes[LayoutUtil.MIN] = maxEnd;
- if (curSizes[LayoutUtil.PREF] < maxEnd)
- curSizes[LayoutUtil.PREF] = maxEnd;
- }
-
- private int[] getAbsoluteDimBounds(CompWrap cw, int refSize, boolean isHor)
- {
- if (cw.cc.isExternal()) {
- if (isHor) {
- return new int[] {cw.comp.getX(), cw.comp.getWidth()};
- } else {
- return new int[] {cw.comp.getY(), cw.comp.getHeight()};
- }
- }
-
- int[] plafPad = lc.isVisualPadding() ? cw.comp.getVisualPadding() : null;
- UnitValue[] pad = cw.cc.getPadding();
-
- // If no changes do not create a lot of objects
- if (cw.pos == null && plafPad == null && pad == null)
- return null;
-
- // Set start
- int st = isHor ? cw.x : cw.y;
- int sz = isHor ? cw.w : cw.h;
-
- // If absolute, use those coordinates instead.
- if (cw.pos != null) {
- UnitValue stUV = cw.pos != null ? cw.pos[isHor ? 0 : 1] : null;
- UnitValue endUV = cw.pos != null ? cw.pos[isHor ? 2 : 3] : null;
-
- int minSz = cw.getSize(LayoutUtil.MIN, isHor);
- int maxSz = cw.getSize(LayoutUtil.MAX, isHor);
- sz = Math.min(Math.max(cw.getSize(LayoutUtil.PREF, isHor), minSz), maxSz);
-
- if (stUV != null) {
- st = stUV.getPixels(stUV.getUnit() == UnitValue.ALIGN ? sz : refSize, container, cw.comp);
-
- if (endUV != null) // if (endUV == null && cw.cc.isBoundsIsGrid() == true)
- sz = Math.min(Math.max((isHor ? (cw.x + cw.w) : (cw.y + cw.h)) - st, minSz), maxSz);
- }
-
- if (endUV != null) {
- if (stUV != null) { // if (stUV != null || cw.cc.isBoundsIsGrid()) {
- sz = Math.min(Math.max(endUV.getPixels(refSize, container, cw.comp) - st, minSz), maxSz);
- } else {
- st = endUV.getPixels(refSize, container, cw.comp) - sz;
- }
- }
- }
-
- // If constraint has padding -> correct the start/size
- if (pad != null) {
- UnitValue uv = pad[isHor ? 1 : 0];
- int p = uv != null ? uv.getPixels(refSize, container, cw.comp) : 0;
- st += p;
- uv = pad[isHor ? 3 : 2];
- sz += -p + (uv != null ? uv.getPixels(refSize, container, cw.comp) : 0);
- }
-
- // If the plaf converter has padding -> correct the start/size
- if (plafPad != null) {
- int p = plafPad[isHor ? 1 : 0];
- st += p;
- sz += -p + (plafPad[isHor ? 3 : 2]);
- }
-
- return new int[] {st, sz};
- }
-
- private void layoutInOneDim(int refSize, UnitValue align, boolean isRows, Float[] defaultGrowW)
- {
- boolean fromEnd = !(isRows ? lc.isTopToBottom() : LayoutUtil.isLeftToRight(lc, container));
- DimConstraint[] primDCs = (isRows ? rowConstr : colConstr).getConstaints();
- FlowSizeSpec fss = isRows ? rowFlowSpecs : colFlowSpecs;
- ArrayList<LinkedDimGroup>[] rowCols = isRows ? rowGroupLists : colGroupLists;
-
- int[] rowColSizes = LayoutUtil.calculateSerial(fss.sizes, fss.resConstsInclGaps, defaultGrowW, LayoutUtil.PREF, refSize);
-
- if (LayoutUtil.isDesignTime(container)) {
- TreeSet<Integer> indexes = isRows ? rowIndexes : colIndexes;
- int[] ixArr = new int[indexes.size()];
- int ix = 0;
- for (Integer i : indexes)
- ixArr[ix++] = i.intValue();
-
- putSizesAndIndexes(container.getComponent(), rowColSizes, ixArr, isRows);
- }
-
- int curPos = align != null ? Math.round(align.getPixels(refSize - LayoutUtil.sum(rowColSizes), container, null)) : 0;
-
- if (fromEnd)
- curPos = refSize - curPos;
-
- for (int i = 0 ; i < rowCols.length; i++) {
- ArrayList<LinkedDimGroup> linkedGroups = rowCols[i];
- int scIx = i - (isRows ? dockOffY : dockOffX);
-
- int bIx = i << 1;
- int bIx2 = bIx + 1;
-
- curPos += (fromEnd ? -rowColSizes[bIx] : rowColSizes[bIx]);
-
- DimConstraint primDC = scIx >= 0 ? primDCs[scIx >= primDCs.length ? primDCs.length - 1 : scIx] : DOCK_DIM_CONSTRAINT;
-
- int rowSize = rowColSizes[bIx2];
-
- for (int j = 0; j < linkedGroups.size(); j++) {
- LinkedDimGroup group = linkedGroups.get(j);
- int groupSize = rowSize;
- if (group.span > 1)
- groupSize = LayoutUtil.sum(rowColSizes, bIx2, Math.min((group.span << 1) - 1, rowColSizes.length - bIx2 - 1));
-
- group.layout(primDC, curPos, groupSize, group.span);
- }
-
- curPos += (fromEnd ? -rowSize : rowSize);
- }
- }
-
- private void addToSizeGroup(HashMap<String, int[]> sizeGroups, String sizeGroup, int[] size)
- {
- if (sizeGroups == null)
- return;
-
- int[] sgSize = sizeGroups.get(sizeGroup);
- if (sgSize == null) {
- sizeGroups.put(sizeGroup, new int[] {size[LayoutUtil.MIN], size[LayoutUtil.PREF], size[LayoutUtil.MAX]});
- } else {
- sgSize[LayoutUtil.MIN] = Math.max(size[LayoutUtil.MIN], sgSize[LayoutUtil.MIN]);
- sgSize[LayoutUtil.PREF] = Math.max(size[LayoutUtil.PREF], sgSize[LayoutUtil.PREF]);
- sgSize[LayoutUtil.MAX] = Math.min(size[LayoutUtil.MAX], sgSize[LayoutUtil.MAX]);
- }
- }
-
- private HashMap<String, Integer> addToEndGroup(HashMap<String, Integer> endGroups, String endGroup, int end)
- {
- if (endGroup != null) {
- if (endGroups == null)
- endGroups = new HashMap<String, Integer>(2);
-
- Integer oldEnd = endGroups.get(endGroup);
- if (oldEnd == null || end > oldEnd.intValue())
- endGroups.put(endGroup, new Integer(end));
- }
- return endGroups;
- }
-
- /** Calculates Min, Preferred and Max size for the columns OR rows.
- * @param defGrow The default grow weight if the specs does not have anyone that will grow. Comes from "push" in the CC.
- * @return The sizes in a {@link net.miginfocom.layout.Grid.FlowSizeSpec}.
- */
- private FlowSizeSpec calcRowsOrColsSizes(ArrayList<LinkedDimGroup>[] groupsLists, Float[] defGrow, int refSize, boolean isHor)
- {
- DimConstraint[] primDCs = (isHor? colConstr : rowConstr).getConstaints();
- TreeSet<Integer> primIdexes = isHor ? colIndexes : rowIndexes;
-
- int[][] rowColBoundSizes = new int[primIdexes.size()][];
- HashMap<String, int[]> sizeGroupMap = new HashMap<String, int[]>(2);
- DimConstraint[] allDCs = new DimConstraint[primIdexes.size()];
-
- Iterator<Integer> primIt = primIdexes.iterator();
- for (int r = 0; r < rowColBoundSizes.length; r++) {
- int cellIx = primIt.next().intValue();
- int[] rowColSizes = new int[3];
-
- if (cellIx >= -MAX_GRID && cellIx <= MAX_GRID) { // If not dock cell
- allDCs[r] = primDCs[cellIx >= primDCs.length ? primDCs.length - 1 : cellIx];
- } else {
- allDCs[r] = DOCK_DIM_CONSTRAINT;
- }
-
- ArrayList<LinkedDimGroup> groups = groupsLists[r];
-
- int[] groupSizes = new int[] {
- getTotalGroupsSizeParallel(groups, LayoutUtil.MIN, false),
- getTotalGroupsSizeParallel(groups, LayoutUtil.PREF, false),
- LayoutUtil.INF};
-
- correctMinMax(groupSizes);
- BoundSize dimSize = allDCs[r].getSize();
-
- for (int sType = LayoutUtil.MIN; sType <= LayoutUtil.MAX; sType++) {
-
- int rowColSize = groupSizes[sType];
-
- UnitValue uv = dimSize != null ? dimSize.getSize(sType) : null;
- if (uv != null) {
- // If the size of the column is a link to some other size, use that instead
- int unit = uv.getUnit();
- if (unit == UnitValue.PREF_SIZE) {
- rowColSize = groupSizes[LayoutUtil.PREF];
- } else if (unit == UnitValue.MIN_SIZE) {
- rowColSize = groupSizes[LayoutUtil.MIN];
- } else if (unit == UnitValue.MAX_SIZE) {
- rowColSize = groupSizes[LayoutUtil.MAX];
- } else {
- rowColSize = uv.getPixels(refSize, container, null);
- }
- } else if (cellIx >= -MAX_GRID && cellIx <= MAX_GRID && rowColSize == 0) {
- rowColSize = LayoutUtil.isDesignTime(container) ? LayoutUtil.getDesignTimeEmptySize() : 0; // Empty rows with no size set gets XX pixels if design time
- }
-
- rowColSizes[sType] = rowColSize;
- }
-
- correctMinMax(rowColSizes);
- addToSizeGroup(sizeGroupMap, allDCs[r].getSizeGroup(), rowColSizes);
-
- rowColBoundSizes[r] = rowColSizes;
- }
-
- // Set/equalize the size groups to same the values.
- if (sizeGroupMap.size() > 0) {
- for (int r = 0; r < rowColBoundSizes.length; r++) {
- if (allDCs[r].getSizeGroup() != null)
- rowColBoundSizes[r] = sizeGroupMap.get(allDCs[r].getSizeGroup());
- }
- }
-
- // Add the gaps
- ResizeConstraint[] resConstrs = getRowResizeConstraints(allDCs);
-
- boolean[] fillInPushGaps = new boolean[allDCs.length + 1];
- int[][] gapSizes = getRowGaps(allDCs, refSize, isHor, fillInPushGaps);
-
-
- FlowSizeSpec fss = mergeSizesGapsAndResConstrs(resConstrs, fillInPushGaps, rowColBoundSizes, gapSizes, refSize, container);
-
- // Spanning components are not handled yet. Check and adjust the multi-row min/pref they enforce.
- adjustMinPrefForSpanningComps(allDCs, defGrow, fss, groupsLists);
-
- return fss;
- }
-
- private static int[] getMinPrefMaxSumSize(int[][] sizes)
- {
- int[] retSizes = new int[3];
-
- for (int i = 0; i < sizes.length; i++) {
- if (sizes[i] != null) {
- int[] size = sizes[i];
- for (int sType = LayoutUtil.MIN; sType <= LayoutUtil.MAX; sType++) {
- int s = size[sType];
-
- if (s != LayoutUtil.NOT_SET) {
- if (sType == LayoutUtil.PREF) {
- int bnd = size[LayoutUtil.MAX];
- if (bnd != LayoutUtil.NOT_SET && bnd < s)
- s = bnd;
-
- bnd = size[LayoutUtil.MIN];
- if (bnd > s) // Includes s == LayoutUtil.NOT_SET since < 0.
- s = bnd;
- }
-
- retSizes[sType] += s; // MAX compensated below.
- }
- }
-
- // So that MAX is always correct.
- if (size[LayoutUtil.MAX] == LayoutUtil.NOT_SET)
- retSizes[LayoutUtil.MAX] = LayoutUtil.INF;
- }
- }
-
- return retSizes;
- }
-
- private static ResizeConstraint[] getRowResizeConstraints(DimConstraint[] specs)
- {
- ResizeConstraint[] resConsts = new ResizeConstraint[specs.length];
- for (int i = 0; i < resConsts.length; i++)
- resConsts[i] = specs[i].resize;
- return resConsts;
- }
-
- private static ResizeConstraint[] getComponentResizeConstraints(ArrayList<CompWrap> compWraps, boolean isHor)
- {
- ResizeConstraint[] resConsts = new ResizeConstraint[compWraps.size()];
- for (int i = 0; i < resConsts.length; i++) {
- CC fc = compWraps.get(i).cc;
- resConsts[i] = fc.getDimConstraint(isHor).resize;
-
- // Always grow docking components in the correct dimension.
- int dock = fc.getDockSide();
- if (isHor ? (dock == 0 || dock == 2) : (dock == 1 || dock == 3)) {
- ResizeConstraint dc = resConsts[i];
- resConsts[i] = new ResizeConstraint(dc.shrinkPrio, dc.shrink, dc.growPrio, ResizeConstraint.WEIGHT_100);
- }
- }
- return resConsts;
- }
-
- private static boolean[] getComponentGapPush(ArrayList<CompWrap> compWraps, boolean isHor)
- {
- // Make one element bigger and or the after gap with the next before gap.
- boolean[] barr = new boolean[compWraps.size() + 1];
- for (int i = 0; i < barr.length; i++) {
-
- boolean push = i > 0 ? compWraps.get(i - 1).isPushGap(isHor, false) : false;
-
- if (push == false && i < (barr.length - 1))
- push = compWraps.get(i).isPushGap(isHor, true);
-
- barr[i] = push;
- }
- return barr;
- }
-
- /** Returns the row gaps in pixel sizes. One more than there are <code>specs</code> sent in.
- * @param specs
- * @param refSize
- * @param isHor
- * @param fillInPushGaps If the gaps are pushing. <b>NOTE!</b> this argument will be filled in and thus changed!
- * @return The row gaps in pixel sizes. One more than there are <code>specs</code> sent in.
- */
- private int[][] getRowGaps(DimConstraint[] specs, int refSize, boolean isHor, boolean[] fillInPushGaps)
- {
- BoundSize defGap = isHor ? lc.getGridGapX() : lc.getGridGapY();
- if (defGap == null)
- defGap = isHor ? PlatformDefaults.getGridGapX() : PlatformDefaults.getGridGapY();
- int[] defGapArr = defGap.getPixelSizes(refSize, container, null);
-
- boolean defIns = !hasDocks();
-
- UnitValue firstGap = LayoutUtil.getInsets(lc, isHor ? 1 : 0, defIns);
- UnitValue lastGap = LayoutUtil.getInsets(lc, isHor ? 3 : 2, defIns);
-
- int[][] retValues = new int[specs.length + 1][];
-
- for (int i = 0, wgIx = 0; i < retValues.length; i++) {
- DimConstraint specBefore = i > 0 ? specs[i - 1] : null;
- DimConstraint specAfter = i < specs.length ? specs[i] : null;
-
- // No gap if between docking components.
- boolean edgeBefore = (specBefore == DOCK_DIM_CONSTRAINT || specBefore == null);
- boolean edgeAfter = (specAfter == DOCK_DIM_CONSTRAINT || specAfter == null);
- if (edgeBefore && edgeAfter)
- continue;
-
- BoundSize wrapGapSize = (wrapGapMap == null || isHor == lc.isFlowX() ? null : wrapGapMap.get(new Integer(wgIx++)));
-
- if (wrapGapSize == null) {
-
- int[] gapBefore = specBefore != null ? specBefore.getRowGaps(container, null, refSize, false) : null;
- int[] gapAfter = specAfter != null ? specAfter.getRowGaps(container, null, refSize, true) : null;
-
- if (edgeBefore && gapAfter == null && firstGap != null) {
-
- int bef = firstGap.getPixels(refSize, container, null);
- retValues[i] = new int[] {bef, bef, bef};
-
- } else if (edgeAfter && gapBefore == null && firstGap != null) {
-
- int aft = lastGap.getPixels(refSize, container, null);
- retValues[i] = new int[] {aft, aft, aft};
-
- } else {
- retValues[i] = gapAfter != gapBefore ? mergeSizes(gapAfter, gapBefore) : new int[] {defGapArr[0], defGapArr[1], defGapArr[2]};
- }
-
- if (specBefore != null && specBefore.isGapAfterPush() || specAfter != null && specAfter.isGapBeforePush())
- fillInPushGaps[i] = true;
- } else {
-
- if (wrapGapSize.isUnset()) {
- retValues[i] = new int[] {defGapArr[0], defGapArr[1], defGapArr[2]};
- } else {
- retValues[i] = wrapGapSize.getPixelSizes(refSize, container, null);
- }
- fillInPushGaps[i] = wrapGapSize.getGapPush();
- }
- }
- return retValues;
- }
-
- private static int[][] getGaps(ArrayList<CompWrap> compWraps, boolean isHor)
- {
- int compCount = compWraps.size();
- int[][] retValues = new int[compCount + 1][];
-
- retValues[0] = compWraps.get(0).getGaps(isHor, true);
- for (int i = 0; i < compCount; i++) {
- int[] gap1 = compWraps.get(i).getGaps(isHor, false);
- int[] gap2 = i < compCount - 1 ? compWraps.get(i + 1).getGaps(isHor, true) : null;
-
- retValues[i + 1] = mergeSizes(gap1, gap2);
- }
-
- return retValues;
- }
-
- private boolean hasDocks()
- {
- return (dockOffX > 0 || dockOffY > 0 || rowIndexes.last() > MAX_GRID || colIndexes.last() > MAX_GRID);
- }
-
- /**
- * @param specs The specs for the columns or rows. Last index will be used of <code>count</code> is greater than this array's length.
- * @param defGrow The default grow weight if the specs does not have anyone that will grow. Comes from "push" in the CC.
- * @param fss
- * @param groupsLists
- */
- private void adjustMinPrefForSpanningComps(DimConstraint[] specs, Float[] defGrow, FlowSizeSpec fss, ArrayList<LinkedDimGroup>[] groupsLists)
- {
- for (int r = 0; r < groupsLists.length; r++) {
- ArrayList<LinkedDimGroup> groups = groupsLists[r];
-
- for (int i = 0; i < groups.size(); i++) {
- LinkedDimGroup group = groups.get(i);
- if (group.span == 1)
- continue;
-
- int cSize = group.getMinPrefMax()[LayoutUtil.PREF];
- if (cSize == LayoutUtil.NOT_SET)
- continue;
-
- int rowSize = 0;
- int sIx = (r << 1) + 1;
- int len = Math.min((group.span << 1), fss.sizes.length - sIx) - 1;
- for (int j = sIx; j < sIx + len; j++) {
- int sz = fss.sizes[j][LayoutUtil.PREF];
- if (sz != LayoutUtil.NOT_SET)
- rowSize += sz;
- }
-
- if (rowSize < cSize) {
- for (int eag = 0, newRowSize = 0; eag < 4 && newRowSize < cSize; eag++)
- newRowSize = fss.expandSizes(specs, defGrow, cSize, sIx, len, LayoutUtil.PREF, eag);
- }
- }
- }
- }
-
- /** For one dimension divide the component wraps into logical groups. One group for component wraps that share a common something,
- * line the property to layout by base line.
- * @param isRows If rows, and not columns, are to be divided.
- * @return One <code>ArrayList<LinkedDimGroup></code> for every row/column.
- */
- private ArrayList<LinkedDimGroup>[] divideIntoLinkedGroups(boolean isRows)
- {
- boolean fromEnd = !(isRows ? lc.isTopToBottom() : LayoutUtil.isLeftToRight(lc, container));
- TreeSet<Integer> primIndexes = isRows ? rowIndexes : colIndexes;
- TreeSet<Integer> secIndexes = isRows ? colIndexes : rowIndexes;
- DimConstraint[] primDCs = (isRows ? rowConstr : colConstr).getConstaints();
-
- ArrayList<LinkedDimGroup>[] groupLists = new ArrayList[primIndexes.size()];
-
- int gIx = 0;
- for (Iterator<Integer> primIt = primIndexes.iterator(); primIt.hasNext();) {
- int i = primIt.next().intValue();
-
- DimConstraint dc;
- if (i >= -MAX_GRID && i <= MAX_GRID) { // If not dock cell
- dc = primDCs[i >= primDCs.length ? primDCs.length - 1 : i];
- } else {
- dc = DOCK_DIM_CONSTRAINT;
- }
-
- ArrayList<LinkedDimGroup> groupList = new ArrayList<LinkedDimGroup>(2);
- groupLists[gIx++] = groupList;
-
- for (Iterator<Integer> secIt = secIndexes.iterator(); secIt.hasNext();) {
- int j = secIt.next().intValue();
- Cell cell = isRows ? getCell(i, j) : getCell(j, i);
- if (cell == null || cell.compWraps.size() == 0)
- continue;
-
- int span = (isRows ? cell.spany : cell.spanx);
- if (span > 1)
- span = convertSpanToSparseGrid(i, span, primIndexes);
-
- boolean isPar = cell.flowx == isRows;
-
- if ((isPar == false && cell.compWraps.size() > 1) || span > 1) {
-
- int linkType = isPar ? LinkedDimGroup.TYPE_PARALLEL : LinkedDimGroup.TYPE_SERIAL;
- LinkedDimGroup lg = new LinkedDimGroup("p," + j, span, linkType, !isRows, fromEnd);
- lg.setCompWraps(cell.compWraps);
- groupList.add(lg);
- } else {
- for (int cwIx = 0; cwIx < cell.compWraps.size(); cwIx++) {
- CompWrap cw = cell.compWraps.get(cwIx);
- boolean rowBaselineAlign = (isRows && dc.getAlignOrDefault(!isRows) == UnitValue.BASELINE_IDENTITY);
-
- String linkCtx = cw.getLinkContext(rowBaselineAlign);
-
- // Find a group with same link context and put it in that group.
- boolean foundList = false;
- for (int glIx = 0, lastGl = groupList.size() - 1; glIx <= lastGl ; glIx++) {
- LinkedDimGroup group = groupList.get(glIx);
- if (group.linkCtx == linkCtx || linkCtx != null && linkCtx.equals(group.linkCtx)) {
- group.addCompWrap(cw);
- foundList = true;
- break;
- }
- }
-
- // If none found and at last add a new group.
- if (foundList == false) {
-
- int linkType = LinkedDimGroup.TYPE_PARALLEL;
- if (isRows && cw.isBaselineAlign(rowBaselineAlign))
- linkType = LinkedDimGroup.TYPE_BASELINE;
-
- LinkedDimGroup lg = new LinkedDimGroup(linkCtx, 1, linkType, !isRows, fromEnd);
- lg.addCompWrap(cw);
- groupList.add(lg);
- }
- }
- }
- }
- }
- return groupLists;
- }
-
- /** Spanning is specified in the uncompressed grid number. They can for instance be more than 60000 for the outer
- * edge dock grid cells. When the grid is compressed and indexed after only the cells that area occupied the span
- * is erratic. This method use the row/col indexes and corrects the span to be correct for the compressed grid.
- * @param span The span un the uncompressed grid. <code>LayoutUtil.INF</code> will be interpreted to span the rest
- * of the column/row excluding the surrounding docking components.
- * @param indexes The indexes in the correct dimension.
- * @return The converted span.
- */
- private int convertSpanToSparseGrid(int curIx, int span, TreeSet<Integer> indexes)
- {
- int lastIx = curIx + span;
- int retSpan = 1;
-
- for (Iterator<Integer> it = indexes.iterator(); it.hasNext();) {
- int ix = it.next();
- if (ix <= curIx)
- continue; // We have not arrive to the correct index yet
-
- if (ix >= lastIx)
- break;
-
- retSpan++;
- }
- return retSpan;
- }
-
- private final boolean isCellFree(int r, int c, ArrayList<int[]> occupiedRects)
- {
- if (getCell(r, c) != null)
- return false;
-
- for (int i = 0; i < occupiedRects.size(); i++) {
- int[] rect = occupiedRects.get(i);
- if (rect[0] <= c && rect[1] <= r && rect[0] + rect[2] > c && rect[1] + rect[3] > r)
- return false;
- }
- return true;
- }
-
- private Cell getCell(int r, int c)
- {
- return grid.get(new Integer((r << 16) + c));
- }
-
- private void setCell(int r, int c, Cell cell)
- {
- if (c < 0 || c > MAX_GRID || r < 0 || r > MAX_GRID)
- throw new IllegalArgumentException("Cell position out of bounds. row: " + r + ", col: " + c);
-
- rowIndexes.add(new Integer(r));
- colIndexes.add(new Integer(c));
-
- grid.put(new Integer((r << 16) + c), cell);
- }
-
- /** Adds a docking cell. That cell is outside the normal cell indexes.
- * @param dockInsets The current dock insets. Will be updated!
- * @param side top == 0, left == 1, bottom = 2, right = 3.
- * @param cw The compwrap to put in a cell and add.
- */
- private void addDockingCell(int[] dockInsets, int side, CompWrap cw)
- {
- int r, c, spanx = 1, spany = 1;
- switch (side) {
- case 0:
- case 2:
- r = side == 0 ? dockInsets[0]++ : dockInsets[2]--;
- c = dockInsets[1];
- spanx = dockInsets[3] - dockInsets[1] + 1; // The +1 is for cell 0.
- colIndexes.add(new Integer(dockInsets[3])); // Make sure there is a receiving cell
- break;
-
- case 1:
- case 3:
- c = side == 1 ? dockInsets[1]++ : dockInsets[3]--;
- r = dockInsets[0];
- spany = dockInsets[2] - dockInsets[0] + 1; // The +1 is for cell 0.
- rowIndexes.add(new Integer(dockInsets[2])); // Make sure there is a receiving cell
- break;
-
- default:
- throw new IllegalArgumentException("Internal error 123.");
- }
-
- rowIndexes.add(new Integer(r));
- colIndexes.add(new Integer(c));
-
- grid.put(new Integer((r << 16) + c), new Cell(cw, spanx, spany, spanx > 1));
- }
-
- /** A simple representation of a cell in the grid. Contains a number of component wraps and if they span more than one cell.
- */
- private static class Cell
- {
- private final int spanx, spany;
- private final boolean flowx;
- private final ArrayList<CompWrap> compWraps = new ArrayList<CompWrap>(1);
-
- private boolean hasTagged = false; // If one or more components have styles and need to be checked by the component sorter
-
- private Cell(CompWrap cw)
- {
- this(cw, 1, 1, true);
- }
-
- private Cell(int spanx, int spany, boolean flowx)
- {
- this(null, spanx, spany, flowx);
- }
-
- private Cell(CompWrap cw, int spanx, int spany, boolean flowx)
- {
- if (cw != null)
- compWraps.add(cw);
- this.spanx = spanx;
- this.spany = spany;
- this.flowx = flowx;
- }
- }
-
- /** A number of component wraps that share a layout "something" <b>in one dimension</b>
- */
- private static class LinkedDimGroup
- {
- private static final int TYPE_SERIAL = 0;
- private static final int TYPE_PARALLEL = 1;
- private static final int TYPE_BASELINE = 2;
-
- private final String linkCtx;
- private final int span;
- private final int linkType;
- private final boolean isHor, fromEnd;
-
- private ArrayList<CompWrap> _compWraps = new ArrayList<CompWrap>(4);
-
- private int[] sizes = null;
- private int lStart = 0, lSize = 0; // Currently mostly for debug painting
-
- private LinkedDimGroup(String linkCtx, int span, int linkType, boolean isHor, boolean fromEnd)
- {
- this.linkCtx = linkCtx;
- this.span = span;
- this.linkType = linkType;
- this.isHor = isHor;
- this.fromEnd = fromEnd;
- }
-
- private void addCompWrap(CompWrap cw)
- {
- _compWraps.add(cw);
- sizes = null;
- }
-
- private void setCompWraps(ArrayList<CompWrap> cws)
- {
- if (_compWraps != cws) {
- _compWraps = cws;
- sizes = null;
- }
- }
-
- private void layout(DimConstraint dc, int start, int size, int spanCount)
- {
- lStart = start;
- lSize = size;
-
- if (_compWraps.size() == 0)
- return;
-
- ContainerWrapper parent = _compWraps.get(0).comp.getParent();
- if (linkType == TYPE_PARALLEL) {
- layoutParallel(parent, _compWraps, dc, start, size, isHor, spanCount, fromEnd);
- } else if (linkType == TYPE_BASELINE) {
- layoutBaseline(parent, _compWraps, dc, start, size, LayoutUtil.PREF, spanCount);
- } else {
- layoutSerial(parent, _compWraps, dc, start, size, isHor, spanCount, fromEnd);
- }
- }
-
- /** Returns the min/pref/max sizes for this cell. Returned array <b>must not be altered</b>
- * @return A shared min/pref/max array of sizes. Always of length 3 and never <code>null</code>. Will always be of type STATIC and PIXEL.
- */
- private int[] getMinPrefMax()
- {
- if (sizes == null && _compWraps.size() > 0) {
- sizes = new int[3];
- for (int sType = LayoutUtil.MIN; sType <= LayoutUtil.PREF; sType++) {
- if (linkType == TYPE_PARALLEL) {
- sizes[sType] = getTotalSizeParallel(_compWraps, sType, isHor);
- } else if (linkType == TYPE_BASELINE) {
- int[] aboveBelow = getBaselineAboveBelow(_compWraps, sType, false);
- sizes[sType] = aboveBelow[0] + aboveBelow[1];
- } else {
- sizes[sType] = getTotalSizeSerial(_compWraps, sType, isHor);
- }
- }
- sizes[LayoutUtil.MAX] = LayoutUtil.INF;
- }
- return sizes;
- }
- }
-
- /** Wraps a {@link java.awt.Component} together with its constraint. Caches a lot of information about the component so
- * for instance not the preferred size has to be calculated more than once.
- */
- private final static class CompWrap
- {
- private final ComponentWrapper comp;
- private final CC cc;
- private final UnitValue[] pos;
- private int[][] gaps; // [top,left(actually before),bottom,right(actually after)][min,pref,max]
-
- private final int[] horSizes = new int[3];
- private final int[] verSizes = new int[3];
-
- private int x = LayoutUtil.NOT_SET, y = LayoutUtil.NOT_SET, w = LayoutUtil.NOT_SET, h = LayoutUtil.NOT_SET;
-
- private int forcedPushGaps = 0; // 1 == before, 2 = after. Bitwise.
-
- private CompWrap(ComponentWrapper c, CC cc, int eHideMode, UnitValue[] pos, BoundSize[] callbackSz)
- {
- this.comp = c;
- this.cc = cc;
- this.pos = pos;
-
- if (eHideMode <= 0) {
- BoundSize hBS = (callbackSz != null && callbackSz[0] != null) ? callbackSz[0] : cc.getHorizontal().getSize();
- BoundSize vBS = (callbackSz != null && callbackSz[1] != null) ? callbackSz[1] : cc.getVertical().getSize();
-
- for (int i = LayoutUtil.MIN; i <= LayoutUtil.MAX; i++) {
- horSizes[i] = getSize(hBS, i, true);
- verSizes[i] = getSize(vBS, i, false);
- }
-
- correctMinMax(horSizes);
- correctMinMax(verSizes);
- }
-
- if (eHideMode > 1) {
- gaps = new int[4][];
- for (int i = 0; i < gaps.length; i++)
- gaps[i] = new int[3];
- }
- }
-
- private final int getSize(BoundSize uvs, int sizeType, boolean isHor)
- {
- if (uvs == null || uvs.getSize(sizeType) == null) {
- switch(sizeType) {
- case LayoutUtil.MIN:
- return isHor ? comp.getMinimumWidth() : comp.getMinimumHeight();
- case LayoutUtil.PREF:
- return isHor ? comp.getPreferredWidth() : comp.getPreferredHeight();
- default:
- return isHor ? comp.getMaximumWidth() : comp.getMaximumHeight();
- }
- }
-
- ContainerWrapper par = comp.getParent();
- return uvs.getSize(sizeType).getPixels(isHor ? par.getWidth() : par.getHeight(), par, comp);
- }
-
- private final void calcGaps(ComponentWrapper before, CC befCC, ComponentWrapper after, CC aftCC, String tag, boolean flowX, boolean isLTR)
- {
- ContainerWrapper par = comp.getParent();
- int parW = par.getWidth();
- int parH = par.getHeight();
-
- BoundSize befGap = before != null ? (flowX ? befCC.getHorizontal() : befCC.getVertical()).getGapAfter() : null;
- BoundSize aftGap = after != null ? (flowX ? aftCC.getHorizontal() : aftCC.getVertical()).getGapBefore() : null;
-
- mergeGapSizes(cc.getVertical().getComponentGaps(par, comp, befGap, (flowX ? null : before), tag, parH, 0, isLTR), false, true);
- mergeGapSizes(cc.getHorizontal().getComponentGaps(par, comp, befGap, (flowX ? before : null), tag, parW, 1, isLTR), true, true);
- mergeGapSizes(cc.getVertical().getComponentGaps(par, comp, aftGap, (flowX ? null : after), tag, parH, 2, isLTR), false, false);
- mergeGapSizes(cc.getHorizontal().getComponentGaps(par, comp, aftGap, (flowX ? after : null), tag, parW, 3, isLTR), true, false);
- }
-
- private final void setDimBounds(int start, int size, boolean isHor)
- {
- if (isHor) {
- x = start;
- w = size;
- } else {
- y = start;
- h = size;
- }
- }
-
- private final boolean isPushGap(boolean isHor, boolean isBefore)
- {
- if (isHor && ((isBefore ? 1 : 2) & forcedPushGaps) != 0)
- return true; // Forced
-
- DimConstraint dc = cc.getDimConstraint(isHor);
- BoundSize s = isBefore ? dc.getGapBefore() : dc.getGapAfter();
- return s != null && s.getGapPush();
- }
-
- /**
- * @return If the preferred size have changed because of the new bounds (needed for SWT only)
- */
- private final boolean transferBounds(boolean checkPrefChange)
- {
- comp.setBounds(x, y, w, h);
-
- if (checkPrefChange && w != horSizes[LayoutUtil.PREF]) {
- BoundSize vSz = cc.getVertical().getSize();
- if ((vSz == null || vSz.getPreferred() == null)) {
- if (comp.getPreferredHeight() != verSizes[LayoutUtil.PREF]) {
- //System.out.println(comp.getComponent() + "oldPrefH: " + verSizes[LayoutUtil.PREF] + ", new: " + comp.getPreferredHeight());
- return true;
- }
- }
- }
-
- return false;
- }
-
- private final void setSizes(int[] sizes, boolean isHor)
- {
- if (sizes == null)
- return;
-
- int[] s = isHor ? horSizes : verSizes;
- for (int i = 0; i < 3; i++)
- s[i] = sizes[i];
- }
-
- private void setGaps(int[] minPrefMax, int ix)
- {
- if (gaps == null)
- gaps = new int[][] {null, null, null, null};
-
- gaps[ix] = minPrefMax;
- }
-
- private final void mergeGapSizes(int[] sizes, boolean isHor, boolean isTL)
- {
- if (gaps == null)
- gaps = new int[][] {null, null, null, null};
-
- if (sizes == null)
- return;
-
- int gapIX = getGapIx(isHor, isTL);
- int[] oldGaps = gaps[gapIX];
- if (oldGaps == null) {
- oldGaps = new int[] {0, 0, LayoutUtil.INF};
- gaps[gapIX] = oldGaps;
- }
-
- oldGaps[LayoutUtil.MIN] = Math.max(sizes[LayoutUtil.MIN], oldGaps[LayoutUtil.MIN]);
- oldGaps[LayoutUtil.PREF] = Math.max(sizes[LayoutUtil.PREF], oldGaps[LayoutUtil.PREF]);
- oldGaps[LayoutUtil.MAX] = Math.min(sizes[LayoutUtil.MAX], oldGaps[LayoutUtil.MAX]);
- }
-
- private final int getGapIx(boolean isHor, boolean isTL)
- {
- return isHor ? (isTL ? 1 : 3) : (isTL ? 0 : 2);
- }
-
- private final String getLinkContext(boolean defBaseline)
- {
- return isBaselineAlign(defBaseline) ? "baseline" : null;
- }
-
- private final int getSizeInclGaps(int sizeType, boolean isHor)
- {
- return filter(sizeType, getGapBefore(sizeType, isHor) + getSize(sizeType, isHor) + getGapAfter(sizeType, isHor));
- }
-
- private final int getSize(int sizeType, boolean isHor)
- {
- return filter(sizeType, isHor ? horSizes[sizeType] : verSizes[sizeType]);
- }
-
- private final int getGapBefore(int sizeType, boolean isHor)
- {
- int[] gaps = getGaps(isHor, true);
- return gaps != null ? filter(sizeType, gaps[sizeType]) : 0;
- }
-
- private final int getGapAfter(int sizeType, boolean isHor)
- {
- int[] gaps = getGaps(isHor, false);
- return gaps != null ? filter(sizeType, gaps[sizeType]) : 0;
- }
-
- private final int[] getGaps(boolean isHor, boolean isTL)
- {
- return gaps[getGapIx(isHor, isTL)];
- }
-
- private final int filter(int sizeType, int size)
- {
- if (size == LayoutUtil.NOT_SET)
- return sizeType != LayoutUtil.MAX ? 0 : LayoutUtil.INF;
- return constrainSize(size);
- }
-
- private final boolean isBaselineAlign(boolean defValue)
- {
- Float g = cc.getVertical().getGrow();
- if (g != null && g.intValue() != 0)
- return false;
-
- UnitValue al = cc.getVertical().getAlign();
- return comp.hasBaseline() && (al != null ? al == UnitValue.BASELINE_IDENTITY : defValue);
- }
-
- private final int getBaseline(int sizeType)
- {
- return comp.getBaseline(getSize(sizeType, true), getSize(sizeType, false));
- }
- }
-
- //***************************************************************************************
- //* Helper Methods
- //***************************************************************************************
-
- private static void layoutBaseline(ContainerWrapper parent, ArrayList<CompWrap> compWraps, DimConstraint dc, int start, int size, int sizeType, int spanCount)
- {
- int[] aboveBelow = getBaselineAboveBelow(compWraps, sizeType, true);
- int blRowSize = aboveBelow[0] + aboveBelow[1];
-
- CC cc = compWraps.get(0).cc;
-
- // Align for the whole baseline component array
- UnitValue align = cc.getVertical().getAlign();
- if (spanCount == 1 && align == null)
- align = dc.getAlignOrDefault(false);
- if (align == UnitValue.BASELINE_IDENTITY)
- align = UnitValue.CENTER;
-
- int offset = start + aboveBelow[0] + (align != null ? Math.max(0, align.getPixels(size - blRowSize, parent, null)) : 0);
- for (int i = 0, iSz = compWraps.size(); i < iSz; i++) {
- CompWrap cw = compWraps.get(i);
- cw.y += offset;
-
- if (cw.y + cw.h > start + size)
- cw.h = start + size - cw.y;
- }
- }
-
- private static void layoutSerial(ContainerWrapper parent, ArrayList<CompWrap> compWraps, DimConstraint dc, int start, int size, boolean isHor, int spanCount, boolean fromEnd)
- {
- FlowSizeSpec fss = mergeSizesGapsAndResConstrs(
- getComponentResizeConstraints(compWraps, isHor),
- getComponentGapPush(compWraps, isHor),
- getComponentSizes(compWraps, isHor),
- getGaps(compWraps, isHor),
- 0, null);
-
- Float[] growW = dc.isFill() ? GROW_100 : null;
- int[] sizes = LayoutUtil.calculateSerial(fss.sizes, fss.resConstsInclGaps, growW, LayoutUtil.PREF, size);
- setCompWrapBounds(parent, sizes, compWraps, dc.getAlignOrDefault(isHor), start, size, isHor, fromEnd);
- }
-
- private static void setCompWrapBounds(ContainerWrapper parent, int[] allSizes, ArrayList<CompWrap> compWraps, UnitValue rowAlign, int start, int size, boolean isHor, boolean fromEnd)
- {
- int totSize = LayoutUtil.sum(allSizes);
- CC cc = compWraps.get(0).cc;
- UnitValue align = correctAlign(cc, rowAlign, isHor, fromEnd);
-
- int cSt = start;
- int slack = size - totSize;
- if (slack > 0 && align != null) {
- int al = Math.min(slack, Math.max(0, align.getPixels(slack, parent, null)));
- cSt += (fromEnd ? -al : al);
- }
-
- for (int i = 0, bIx = 0, iSz = compWraps.size(); i < iSz; i++) {
- CompWrap cw = compWraps.get(i);
- if (fromEnd ) {
- cSt -= allSizes[bIx++];
- cw.setDimBounds(cSt - allSizes[bIx], allSizes[bIx], isHor);
- cSt -= allSizes[bIx++];
- } else {
- cSt += allSizes[bIx++];
- cw.setDimBounds(cSt, allSizes[bIx], isHor);
- cSt += allSizes[bIx++];
- }
- }
- }
-
- private static void layoutParallel(ContainerWrapper parent, ArrayList<CompWrap> compWraps, DimConstraint dc, int start, int size, boolean isHor, int spanCount, boolean fromEnd)
- {
- int[][] sizes = new int[compWraps.size()][]; // [compIx][gapBef,compSize,gapAft]
-
- for (int i = 0; i < sizes.length; i++) {
- CompWrap cw = compWraps.get(i);
-
- DimConstraint cDc = cw.cc.getDimConstraint(isHor);
-
- ResizeConstraint[] resConstr = new ResizeConstraint[] {
- cw.isPushGap(isHor, true) ? GAP_RC_CONST_PUSH : GAP_RC_CONST,
- cDc.resize,
- cw.isPushGap(isHor, false) ? GAP_RC_CONST_PUSH : GAP_RC_CONST,
- };
-
- int[][] sz = new int[][] {
- cw.getGaps(isHor, true), (isHor ? cw.horSizes : cw.verSizes), cw.getGaps(isHor, false)
- };
-
- Float[] growW = dc.isFill() ? GROW_100 : null;
-
- sizes[i] = LayoutUtil.calculateSerial(sz, resConstr, growW, LayoutUtil.PREF, size);
- }
-
- UnitValue rowAlign = dc.getAlignOrDefault(isHor);
- setCompWrapBounds(parent, sizes, compWraps, rowAlign, start, size, isHor, fromEnd);
- }
-
- private static void setCompWrapBounds(ContainerWrapper parent, int[][] sizes, ArrayList<CompWrap> compWraps, UnitValue rowAlign, int start, int size, boolean isHor, boolean fromEnd)
- {
- for (int i = 0; i < sizes.length; i++) {
- CompWrap cw = compWraps.get(i);
-
- UnitValue align = correctAlign(cw.cc, rowAlign, isHor, fromEnd);
-
- int[] cSizes = sizes[i];
- int gapBef = cSizes[0];
- int cSize = cSizes[1]; // No Math.min(size, cSizes[1]) here!
- int gapAft = cSizes[2];
-
- int cSt = fromEnd ? start - gapBef : start + gapBef;
- int slack = size - cSize - gapBef - gapAft;
- if (slack > 0 && align != null) {
- int al = Math.min(slack, Math.max(0, align.getPixels(slack, parent, null)));
- cSt += (fromEnd ? -al : al);
- }
-
- cw.setDimBounds(fromEnd ? cSt - cSize : cSt, cSize, isHor);
- }
- }
-
- private static UnitValue correctAlign(CC cc, UnitValue rowAlign, boolean isHor, boolean fromEnd)
- {
- UnitValue align = (isHor ? cc.getHorizontal() : cc.getVertical()).getAlign();
- if (align == null)
- align = rowAlign;
- if (align == UnitValue.BASELINE_IDENTITY)
- align = UnitValue.CENTER;
-
- if (fromEnd) {
- if (align == UnitValue.LEFT)
- align = UnitValue.RIGHT;
- else if (align == UnitValue.RIGHT)
- align = UnitValue.LEFT;
- }
- return align;
- }
-
- private static int[] getBaselineAboveBelow(ArrayList<CompWrap> compWraps, int sType, boolean centerBaseline)
- {
- int maxAbove = Short.MIN_VALUE;
- int maxBelow = Short.MIN_VALUE;
- for (int i = 0, iSz = compWraps.size(); i < iSz; i++) {
- CompWrap cw = compWraps.get(i);
-
- int height = cw.getSize(sType, false);
- if (height >= LayoutUtil.INF)
- return new int[] {LayoutUtil.INF / 2, LayoutUtil.INF / 2};
-
- int baseline = cw.getBaseline(sType);
- int above = baseline + cw.getGapBefore(sType, false);
- maxAbove = Math.max(above, maxAbove);
- maxBelow = Math.max(height - baseline + cw.getGapAfter(sType, false), maxBelow);
-
- if (centerBaseline)
- cw.setDimBounds(-baseline, height, false);
- }
- return new int[] {maxAbove, maxBelow};
- }
-
- private static int getTotalSizeParallel(ArrayList<CompWrap> compWraps, int sType, boolean isHor)
- {
- int size = sType == LayoutUtil.MAX ? LayoutUtil.INF : 0;
-
- for (int i = 0, iSz = compWraps.size(); i < iSz; i++) {
- CompWrap cw = compWraps.get(i);
- int cwSize = cw.getSizeInclGaps(sType, isHor);
- if (cwSize >= LayoutUtil.INF)
- return LayoutUtil.INF;
-
- if (sType == LayoutUtil.MAX ? cwSize < size : cwSize > size)
- size = cwSize;
- }
- return constrainSize(size);
- }
-
- private static final int getTotalSizeSerial(ArrayList<CompWrap> compWraps, int sType, boolean isHor)
- {
- int totSize = 0;
- for (int i = 0, iSz = compWraps.size(), lastGapAfter = 0; i < iSz; i++) {
- CompWrap wrap = compWraps.get(i);
- int gapBef = wrap.getGapBefore(sType, isHor);
- if (gapBef > lastGapAfter)
- totSize += gapBef - lastGapAfter;
-
- totSize += wrap.getSize(sType, isHor);
- totSize += (lastGapAfter = wrap.getGapAfter(sType, isHor));
-
- if (totSize >= LayoutUtil.INF)
- return LayoutUtil.INF;
- }
- return constrainSize(totSize);
- }
-
- private static final int getTotalGroupsSizeParallel(ArrayList<LinkedDimGroup> groups, int sType, boolean countSpanning)
- {
- int size = sType == LayoutUtil.MAX ? LayoutUtil.INF : 0;
- for (int i = 0, iSz = groups.size(); i < iSz; i++) {
- LinkedDimGroup group = groups.get(i);
- if (countSpanning || group.span == 1) {
- int grpSize = group.getMinPrefMax()[sType];
- if (grpSize >= LayoutUtil.INF)
- return LayoutUtil.INF;
-
- if (sType == LayoutUtil.MAX ? grpSize < size : grpSize > size)
- size = grpSize;
- }
- }
- return constrainSize(size);
- }
-
- /**
- * @param compWraps
- * @param isHor
- * @return Might contain LayoutUtil.NOT_SET
- */
- private static int[][] getComponentSizes(ArrayList<CompWrap> compWraps, boolean isHor)
- {
- int[][] compSizes = new int[compWraps.size()][];
- for (int i = 0; i < compSizes.length; i++) {
- CompWrap cw = compWraps.get(i);
- compSizes[i] = isHor ? cw.horSizes : cw.verSizes;
- }
- return compSizes;
- }
-
- /** Merges sizes and gaps together with Resize Constraints. For gaps {@link #GAP_RC_CONST} is used.
- * @param resConstr One resize constriant for every row/component. Can be lesser in length and the last element should be used for missing elements.
- * @param gapPush If the corresponding gap should be considered pushing and thus want to take free space if left over. Should be one more than resConstrs!
- * @param minPrefMaxSizes The sizes (min/pref/max) for every row/component.
- * @param gapSizes The gaps before and after each row/component packed in one double sized array.
- * @param refSize The reference size to get the gap in pixels.
- * @param parent The parent used to get the gap in pixels.
- * @return A holder for the merged values.
- */
- private static FlowSizeSpec mergeSizesGapsAndResConstrs(ResizeConstraint[] resConstr, boolean[] gapPush, int[][] minPrefMaxSizes, int[][] gapSizes, int refSize, ContainerWrapper parent)
- {
- int[][] sizes = new int[(minPrefMaxSizes.length << 1) + 1][]; // Make room for gaps around.
- ResizeConstraint[] resConstsInclGaps = new ResizeConstraint[sizes.length];
-
- sizes[0] = gapSizes[0];
- for (int i = 0, crIx = 1; i < minPrefMaxSizes.length; i++, crIx += 2) {
-
- // Component bounds and constraints
- resConstsInclGaps[crIx] = resConstr[i];
- sizes[crIx] = minPrefMaxSizes[i];
-
- sizes[crIx + 1] = gapSizes[i + 1];
-
- if (sizes[crIx - 1] != null)
- resConstsInclGaps[crIx - 1] = gapPush[i < gapPush.length ? i : gapPush.length - 1] ? GAP_RC_CONST_PUSH : GAP_RC_CONST;
-
- if (i == (minPrefMaxSizes.length - 1) && sizes[crIx + 1] != null)
- resConstsInclGaps[crIx + 1] = gapPush[(i + 1) < gapPush.length ? (i + 1) : gapPush.length - 1] ? GAP_RC_CONST_PUSH : GAP_RC_CONST;
- }
-
- // Check for null and set it to 0, 0, 0.
- for (int i = 0; i < sizes.length; i++) {
- if (sizes[i] == null)
- sizes[i] = new int[3];
- }
-
- return new FlowSizeSpec(sizes, resConstsInclGaps);
- }
-
- private static final int[] mergeSizes(int[] oldValues, int[] newValues)
- {
- if (oldValues == null)
- return newValues;
-
- if (newValues == null)
- return oldValues;
-
- int[] ret = new int[oldValues.length];
- for (int i = 0; i < ret.length; i++)
- ret[i] = mergeSizes(oldValues[i], newValues[i], true);
-
- return ret;
- }
-
- private static final int mergeSizes(int oldValue, int newValue, boolean toMax)
- {
- if (oldValue == LayoutUtil.NOT_SET || oldValue == newValue)
- return newValue;
-
- if (newValue == LayoutUtil.NOT_SET)
- return oldValue;
-
- return toMax != oldValue > newValue ? newValue : oldValue;
- }
-
- private static final int constrainSize(int s)
- {
- return s > 0 ? (s < LayoutUtil.INF ? s : LayoutUtil.INF) : 0;
- }
-
- private static final void correctMinMax(int s[])
- {
- if (s[LayoutUtil.MIN] > s[LayoutUtil.MAX])
- s[LayoutUtil.MIN] = s[LayoutUtil.MAX]; // Since MAX is almost always explicitly set use tha
-
- if (s[LayoutUtil.PREF] < s[LayoutUtil.MIN])
- s[LayoutUtil.PREF] = s[LayoutUtil.MIN];
-
- if (s[LayoutUtil.PREF] > s[LayoutUtil.MAX])
- s[LayoutUtil.PREF] = s[LayoutUtil.MAX];
- }
-
- private static final class FlowSizeSpec
- {
- private final int[][] sizes;
- private final ResizeConstraint[] resConstsInclGaps;
-
- private FlowSizeSpec(int[][] sizes, ResizeConstraint[] resConstsInclGaps)
- {
- this.sizes = sizes;
- this.resConstsInclGaps = resConstsInclGaps;
- }
-
- /**
- * @param specs The specs for the columns or rows. Last index will be used of <code>fromIx + len</code> is greater than this array's length.
- * @param targetSize The size to try to meat.
- * @param defGrow The default grow weight if the specs does not have anyone that will grow. Comes from "push" in the CC.
- * @param fromIx
- * @param len
- * @param sizeType
- * @param eagerness How eager the algorithm should be to try to expand the sizes.
- * <ul>
- * <li>0 - Grow only rows/columns which has the <code>sizeType</code> set to be the containing components AND which has a grow weight > 0.
- * <li>1 - Grow only rows/columns which has the <code>sizeType</code> set to be the containing components AND which has a grow weight > 0 OR unspecified.
- * <li>2 - Grow all rows/columns that has a grow weight > 0.
- * <li>3 - Grow all rows/columns that has a grow weight > 0 OR unspecified.
- * </ul>
- * @return The new size.
- */
- private final int expandSizes(DimConstraint[] specs, Float[] defGrow, int targetSize, int fromIx, int len, int sizeType, int eagerness)
- {
- ResizeConstraint[] resConstr = new ResizeConstraint[len];
- int[][] sizesToExpand = new int[len][];
- for (int i = 0; i < len; i++) {
- int size = sizes[i + fromIx][sizeType];
- sizesToExpand[i] = new int[] {size, size, sizes[i + fromIx][LayoutUtil.MAX]};
-
- if (eagerness <= 1 && i % 2 == 0) { // // (i % 2 == 0) means only odd indexes, which is only rows/col indexes and not gaps.
- int cIx = (i + fromIx - 1) >> 1;
- DimConstraint spec = (DimConstraint) LayoutUtil.getIndexSafe(specs, cIx);
-
- if ( (sizeType == LayoutUtil.MIN && spec.getSize() != null && spec.getSize().getMin() != null && spec.getSize().getMin().getUnit() != UnitValue.MIN_SIZE) ||
- (sizeType == LayoutUtil.PREF && spec.getSize() != null && spec.getSize().getPreferred() != null && spec.getSize().getPreferred().getUnit() != UnitValue.PREF_SIZE)) {
- continue;
- }
- }
- resConstr[i] = (ResizeConstraint) LayoutUtil.getIndexSafe(resConstsInclGaps, i + fromIx);
- }
-
- Float[] growW = (eagerness == 1 || eagerness == 3) ? extractSubArray(specs, defGrow, fromIx, len): null;
- int[] newSizes = LayoutUtil.calculateSerial(sizesToExpand, resConstr, growW, sizeType, targetSize);
- int newSize = 0;
-
- for (int i = 0; i < len; i++) {
- int s = newSizes[i];
- sizes[i + fromIx][sizeType] = s;
- newSize += s;
- }
- return newSize;
- }
- }
-
- private static Float[] extractSubArray(DimConstraint[] specs, Float[] arr, int ix, int len)
- {
- if (arr == null || arr.length < ix + len) {
- Float[] growLastArr = new Float[len];
-
- // Handle a group where some rows (first one/few and/or last one/few) are docks.
- for (int i = ix + len - 1; i >= 0; i -= 2) {
- int specIx = (i >> 1);
- if (specs[specIx] != DOCK_DIM_CONSTRAINT) {
- growLastArr[i - ix] = ResizeConstraint.WEIGHT_100;
- return growLastArr;
- }
- }
- return growLastArr;
- }
-
- Float[] newArr = new Float[len];
- for (int i = 0; i < len; i++)
- newArr[i] = arr[ix + i];
- return newArr;
- }
-
- private static WeakHashMap[] PARENT_ROWCOL_SIZES_MAP = null;
- static synchronized void putSizesAndIndexes(Object parComp, int[] sizes, int[] ixArr, boolean isRows)
- {
- if (PARENT_ROWCOL_SIZES_MAP == null) // Lazy since only if designing in IDEs
- PARENT_ROWCOL_SIZES_MAP = new WeakHashMap[] {new WeakHashMap(4), new WeakHashMap(4)};
-
- PARENT_ROWCOL_SIZES_MAP[isRows ? 0 : 1].put(parComp, new int[][] {ixArr, sizes});
- }
-
- static synchronized int[][] getSizesAndIndexes(Object parComp, boolean isRows)
- {
- if (PARENT_ROWCOL_SIZES_MAP == null)
- return null;
-
- return (int[][]) PARENT_ROWCOL_SIZES_MAP[isRows ? 0 : 1].get(parComp);
- }
-}
+package net.miginfocom.layout; + + +import java.util.*; +/* + * License (BSD): + * ============== + * + * Copyright (c) 2004, Mikael Grev, MiG InfoCom AB. (miglayout (at) miginfocom (dot) com) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright notice, this list + * of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * Neither the name of the MiG InfoCom AB nor the names of its contributors may be + * used to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * @version 1.0 + * @author Mikael Grev, MiG InfoCom AB + * Date: 2006-sep-08 + */ + +/** Holds components in a grid. Does most of the logic behind the layout manager. + */ +public final class Grid +{ + public static final boolean TEST_GAPS = true; + + private static final Float[] GROW_100 = new Float[] {ResizeConstraint.WEIGHT_100}; + + private static final DimConstraint DOCK_DIM_CONSTRAINT = new DimConstraint(); + static { + DOCK_DIM_CONSTRAINT.setGrowPriority(0); + } + + /** This is the maximum grid position for "normal" components. Docking components use the space out to + * <code>MAX_DOCK_GRID</code> and below 0. + */ + private static final int MAX_GRID = 30000; + + /** Docking components will use the grid coordinates <code>-MAX_DOCK_GRID -> 0</code> and <code>MAX_GRID -> MAX_DOCK_GRID</code>. + */ + private static final int MAX_DOCK_GRID = 32767; + + /** A constraint used for gaps. + */ + private static final ResizeConstraint GAP_RC_CONST = new ResizeConstraint(200, ResizeConstraint.WEIGHT_100, 50, null); + private static final ResizeConstraint GAP_RC_CONST_PUSH = new ResizeConstraint(200, ResizeConstraint.WEIGHT_100, 50, ResizeConstraint.WEIGHT_100); + + /** The constraints. Never <code>null</code>. + */ + private final LC lc; + + /** The parent that is layout out and this grid is done for. Never <code>null</code>. + */ + private final ContainerWrapper container; + + /** An x, y array implemented as a sparse array to accomodate for any grid size without wasting memory (or rather 15 bit (0-MAX_GRID * 0-MAX_GRID). + */ + private final LinkedHashMap<Integer, Cell> grid = new LinkedHashMap<Integer, Cell>(); // [(y << 16) + x] -> Cell. null key for absolute positioned compwraps + + private HashMap<Integer, BoundSize> wrapGapMap = null; // Row or Column index depending in the dimension that "raps". Normally row indexes but may be column indexes if "flowy". 0 means before first row/col. + + /** The size of the grid. Row count and column count. + */ + private final TreeSet<Integer> rowIndexes = new TreeSet<Integer>(), colIndexes = new TreeSet<Integer>(); + + /** The row and column specifications. + */ + private final AC rowConstr, colConstr; + + /** The in the constructor calculated min/pref/max sizes of the rows and columns. + */ + private FlowSizeSpec colFlowSpecs = null, rowFlowSpecs = null; + + /** Components that are connectione in one dimension (such as baseline alignment for instance) are grouped together and stored here. + * One for each row/column. + */ + private ArrayList<LinkedDimGroup>[] colGroupLists, rowGroupLists; //[(start)row/col number] + + /** The in the constructor calculated min/pref/max size of the whole grid. + */ + private int[] width = null, height = null; + + /** If debug is on contains the bounds for things to paint when calling {@link ContainerWrapper#paintDebugCell(int, int, int, int)} + */ + private ArrayList<int[]> debugRects = null; // [x, y, width, height] + + /** If any of the absolute coordinates for component bounds has links the name of the target is in this Set. + * Since it requires some memory and computations this is checked at the creation so that + * the link information is only created if needed later. + * <p> + * The boolean is true for groups id:s and null for normal id:s. + */ + private HashMap<String, Boolean> linkTargetIDs = null; + + private final int dockOffY, dockOffX; + + private final Float[] growXs, growYs; + + private final ArrayList<LayoutCallback> callbackList; + + /** Constructor. + * @param container The container that will be laid out. + * @param lc The form flow constraints. + * @param rowConstr The rows specifications. If more cell rows are required, the last element will be used for when there is no corresponding element in this array. + * @param colConstr The columns specifications. If more cell rows are required, the last element will be used for when there is no corresponding element in this array. + * @param fcMap The map containing the parsed constraints for each child component of <code>parent</code>. Will not be alterted. + * @param callbackList A list of callbacks or <code>null</code> if none. Will not be alterted. + */ + public Grid(ContainerWrapper container, LC lc, AC rowConstr, AC colConstr, Map<ComponentWrapper, CC> fcMap, ArrayList<LayoutCallback> callbackList) + { + this.lc = lc; + this.rowConstr = rowConstr; + this.colConstr = colConstr; + this.container = container; + this.callbackList = callbackList; + + int wrap = lc.getWrapAfter() != 0 ? lc.getWrapAfter() : (lc.isFlowX() ? colConstr : rowConstr).getConstaints().length; + + final ComponentWrapper[] comps = container.getComponents(); + + boolean hasTagged = false; // So we do not have to sort if it will not do any good + boolean hasPushX = false, hasPushY = false; + final int[] p = new int[2]; + final ArrayList<int[]> spannedRects = new ArrayList<int[]>(2); + + final DimConstraint[] specs = (lc.isFlowX() ? rowConstr : colConstr).getConstaints(); + + int sizeGroupsX = 0, sizeGroupsY = 0; + int[] dockInsets = null; // top, left, bottom, right insets for docks. + + LinkHandler.clearTemporaryBounds(container.getLayout()); + + for (int i = 0; i < comps.length;) { + ComponentWrapper comp = comps[i]; + CC rootCc = fcMap.get(comp); + + int hideMode = comp.isVisible() ? -1 : rootCc.getHideMode() != -1 ? rootCc.getHideMode() : lc.getHideMode(); + + if (rootCc == null || hideMode == 3) { // To work with situations where there are components that does not have a layout manager, or not this one. + if (rootCc != null) + setLinkedBounds(comp, rootCc, comp.getX(), comp.getY(), comp.getWidth(), comp.getHeight(), rootCc.isExternal()); + i++; + continue; // The "external" component should not be handled further. + } + + if (rootCc.getHorizontal().getSizeGroup() != null) + sizeGroupsX++; + if (rootCc.getVertical().getSizeGroup() != null) + sizeGroupsY++; + + // Special treatment of absolute positioned components. + UnitValue[] pos = getPos(comp, rootCc); + BoundSize[] cbSz = getCallbackSize(comp, rootCc); + if (pos != null || rootCc.isExternal()) { + + // Check if link information should be saved later. + if (pos != null) { + for (int l = 0; l < pos.length; l++) { + UnitValue u = pos[l]; + if (u != null && u.isLinkedDeep()) + addLinkTargetIDs(u); + } + } + + CompWrap cw = new CompWrap(comp, rootCc, hideMode, pos, cbSz); + Cell cell = grid.get(null); + if (cell == null) { + grid.put(null, new Cell(cw)); + } else { + cell.compWraps.add(cw); + } + + if (rootCc.isBoundsInGrid() == false || rootCc.isExternal()) { + setLinkedBounds(comp, rootCc, comp.getX(), comp.getY(), comp.getWidth(), comp.getHeight(), rootCc.isExternal()); + i++; + continue; + } + } + + if (rootCc.getDockSide() != -1) { + if (dockInsets == null) + dockInsets = new int[] {-MAX_DOCK_GRID, -MAX_DOCK_GRID, MAX_DOCK_GRID, MAX_DOCK_GRID}; + + addDockingCell(dockInsets, rootCc.getDockSide(), new CompWrap(comp, rootCc, hideMode, pos, cbSz)); + i++; + continue; + } + + Boolean cellFlowX = rootCc.getFlowX(); + Cell cell = null; + + if (rootCc.isNewline()) + wrap(p, rootCc.getNewlineGapSize(), true); + + increase(p, rootCc.getSkip()); // Probably 0 advance... + + boolean rowNoGrid = lc.isNoGrid() || ((DimConstraint) LayoutUtil.getIndexSafe(specs, lc.isFlowX() ? p[1] : p[0])).isNoGrid(); + + // Move to a free y, x if no absolute grid specified + int cx = rootCc.getCellX(); + int cy = rootCc.getCellY(); + if ((cx < 0 || cy < 0) && rowNoGrid == false) { + while (isCellFree(p[1], p[0], spannedRects) == false) { + if (Math.abs(increase(p, 1)) >= wrap) + wrap(p, null, true); + } + } else { + if (cx >= 0 && cy >= 0) { + if (cy >= 0) { + p[0] = cx; + p[1] = cy; + } else { // Only one coordinate is specified. Use the current row (flowx) or column (flowy) to fill in. + if (lc.isFlowX()) { + p[0] = cx; + } else { + p[1] = cx; + } + } + } + cell = getCell(p[1], p[0]); // Might be null + } + + // If cell is not created yet, create it and set it. + if (cell == null) { + int spanx = Math.min(rowNoGrid && lc.isFlowX() ? LayoutUtil.INF : rootCc.getSpanX(), MAX_GRID - p[0]); + int spany = Math.min(rowNoGrid && !lc.isFlowX() ? LayoutUtil.INF : rootCc.getSpanY(), MAX_GRID - p[1]); + + cell = new Cell(spanx, spany, cellFlowX != null ? cellFlowX.booleanValue() : lc.isFlowX()); + + setCell(p[1], p[0], cell); + + // Add a rectangle so we can know that spanned cells occupy more space. + if (spanx > 1 || spany > 1) + spannedRects.add(new int[] {p[0], p[1], spanx, spany}); + } + + // Add the one, or all, components that split the grid position to the same Cell. + boolean forceWrap = false; + BoundSize wrapGap = null; + int splitLeft = rowNoGrid ? LayoutUtil.INF : rootCc.getSplit() - 1; + boolean splitExit = false; + for (; splitLeft >= 0 && forceWrap == false && i < comps.length; splitLeft--) { + ComponentWrapper compAdd = comps[i]; + CC cc = fcMap.get(compAdd); // Can not be null. + + hideMode = compAdd.isVisible() ? -1 : cc.getHideMode() != -1 ? cc.getHideMode() : lc.getHideMode(); + + if (cc == null || cc.isExternal() || hideMode == 3) { + i++; + continue; // To work with situations where there are components that does not have a layout manager, or not this one. + } + + hasPushX |= (cc.getPushX() != null); + hasPushY |= (cc.getPushY() != null); + + if (cc != rootCc) { // If not first in a cell + if (cc.isNewline() || cc.isBoundsInGrid() == false) + break; + + if (splitLeft > 0 && cc.getSkip() > 0) { + splitExit = true; + break; + } + + pos = getPos(compAdd, cc); + cbSz = getCallbackSize(compAdd, cc); + } + + CompWrap cw = new CompWrap(compAdd, cc, hideMode, pos, cbSz); + cell.compWraps.add(cw); + cell.hasTagged |= cc.getTag() != null; + hasTagged |= cell.hasTagged; + + if (cc != rootCc) { + if (cc.getHorizontal().getSizeGroup() != null) + sizeGroupsX++; + if (cc.getVertical().getSizeGroup() != null) + sizeGroupsY++; + } + + int flowSpan = lc.isFlowX() ? rootCc.getSpanX() : rootCc.getSpanY(); + forceWrap = (cc.isWrap() || (flowSpan == LayoutUtil.INF && splitLeft == 0)); + wrapGap = cc.getWrapGapSize(); + i++; + } + + if (forceWrap) { + wrap(p, wrapGap, true); + } else if (rowNoGrid == false) { + int span = lc.isFlowX() ? cell.spanx : cell.spany; + if (Math.abs((lc.isFlowX() ? p[0] : p[1])) + span >= wrap) { + wrap(p, null, true); + } else { + int adv = lc.isFlowX() ? cell.spanx : cell.spany; + if (splitExit) + adv--; + increase(p, adv); + } + } + } + + // If there were size groups, calculate the largest values in the groups (for min/pref/max) and enforce them on the rest in the group. + if (sizeGroupsX > 0 || sizeGroupsY > 0) { + HashMap<String, int[]> sizeGroupMapX = sizeGroupsX > 0 ? new HashMap<String, int[]>(sizeGroupsX) : null; + HashMap<String, int[]> sizeGroupMapY = sizeGroupsY > 0 ? new HashMap<String, int[]>(sizeGroupsY) : null; + ArrayList<CompWrap> sizeGroupCWs = new ArrayList<CompWrap>(Math.max(sizeGroupsX, sizeGroupsY)); + + for (Iterator<Cell> it = grid.values().iterator(); it.hasNext();) { + Cell cell = it.next(); + for (int i = 0; i < cell.compWraps.size(); i++) { + CompWrap cw = cell.compWraps.get(i); + + if (cw.cc.getHorizontal().getSizeGroup() != null || cw.cc.getVertical().getSizeGroup() != null) { + addToSizeGroup(sizeGroupMapX, cw.cc.getHorizontal().getSizeGroup(), cw.horSizes); + addToSizeGroup(sizeGroupMapY, cw.cc.getVertical().getSizeGroup(), cw.verSizes); + sizeGroupCWs.add(cw); + } + } + } + + // Set/equalize the sizeGroups to same the values. + if (sizeGroupCWs != null) { + for (int i = 0; i < sizeGroupCWs.size(); i++) { + CompWrap cw = sizeGroupCWs.get(i); + if (sizeGroupMapX != null) + cw.setSizes(sizeGroupMapX.get(cw.cc.getHorizontal().getSizeGroup()), true); // Target method handles null sizes + if (sizeGroupMapY != null) + cw.setSizes(sizeGroupMapY.get(cw.cc.getVertical().getSizeGroup()), false); // Target method handles null sizes + } + } + } + + if (hasTagged) + sortCellsByPlatform(grid.values(), container); + + // Calculate gaps now that the cells are filled and we know all adjacent components. + boolean ltr = LayoutUtil.isLeftToRight(lc, container); + for (Iterator<Cell> it = grid.values().iterator(); it.hasNext();) { + Cell cell = it.next(); + ArrayList<CompWrap> cws = cell.compWraps; + + for (int i = 0, lastI = cws.size() - 1; i <= lastI; i++) { + CompWrap cw = cws.get(i); + ComponentWrapper cwBef = i > 0 ? cws.get(i - 1).comp : null; + ComponentWrapper cwAft = i < lastI ? cws.get(i + 1).comp : null; + + String tag = fcMap.get(cw.comp).getTag(); + CC ccBef = cwBef != null ? fcMap.get(cwBef) : null; + CC ccAft = cwAft != null ? fcMap.get(cwAft) : null; + + cw.calcGaps(cwBef, ccBef, cwAft, ccAft, tag, cell.flowx, ltr); + } + } + + dockOffX = getDockInsets(colIndexes); + dockOffY = getDockInsets(rowIndexes); + + // Add synthetic indexes for empty rows and columns so they can get a size + for (int i = 0, iSz = rowConstr.getCount(); i < iSz; i++) + rowIndexes.add(new Integer(i)); + for (int i = 0, iSz = colConstr.getCount(); i < iSz; i++) + colIndexes.add(new Integer(i)); + + colGroupLists = divideIntoLinkedGroups(false); + rowGroupLists = divideIntoLinkedGroups(true); + + growXs = getDefaultGrowWeights(hasPushX, false); + growYs = getDefaultGrowWeights(hasPushY, true); + + } + + /** If the container (parent) that this grid is laying out has changed its bounds, call this method to + * clear any cached values. + */ + public void invalidateContainerSize() + { + colFlowSpecs = null; + } + + /** Does the actual layout. Uses many values calculated in the constructor. + * @param bounds The bounds to layout against. Normally that of the parent. [x, y, width, height]. + * @param alignX The alignment for the x-axis. + * @param alignY The alignment for the y-axis. + * @param debug If debug information should be saved in {@link #debugRects}. + * @param checkPrefChange If a check should be done to see if the setting of any new bounds changes the preferred size + * of a component. This is normally only turned on for SWT as SWT has a notion of width vs height calculation. + * @return If the layout has probably change the preferred size and there is need for a new layout (normally only SWT). + */ + public boolean layout(int[] bounds, UnitValue alignX, UnitValue alignY, boolean debug, boolean checkPrefChange) + { + if (debug) + debugRects = new ArrayList<int[]>(); + + checkSizeCalcs(); + + resetLinkValues(true); + + layoutInOneDim(bounds[2], alignX, false, growXs); + layoutInOneDim(bounds[3], alignY, true, growYs); + + HashMap<String, Integer> endGrpXMap = null, endGrpYMap = null; + int compCount = container.getComponentCount(); + + // Transfer the calculated bound from the ComponentWrappers to the actual Components. + boolean layoutAgain = false; + if (compCount > 0) { + for (int j = 0; j < (linkTargetIDs != null ? 2 : 1); j++) { // First do the calculations (maybe more than once) then set the bounds when done + boolean doAgain; + int count = 0; + do { + doAgain = false; + for (Iterator<Cell> it = grid.values().iterator(); it.hasNext();) { + ArrayList<CompWrap> compWraps = it.next().compWraps; + for (int i = 0, iSz = compWraps.size(); i < iSz; i++) { + CompWrap cw = compWraps.get(i); + + if (j == 0) { + doAgain |= doAbsoluteCorrections(cw, bounds); + if (doAgain == false) { // If we are going to do this again, do not bother this time around + if (cw.cc.getHorizontal().getEndGroup() != null) + endGrpXMap = addToEndGroup(endGrpXMap, cw.cc.getHorizontal().getEndGroup(), cw.x + cw.w); + if (cw.cc.getVertical().getEndGroup() != null) + endGrpYMap = addToEndGroup(endGrpYMap, cw.cc.getVertical().getEndGroup(), cw.y + cw.h); + } + } + + if (linkTargetIDs == null || j == 1) { + if (cw.cc.getHorizontal().getEndGroup() != null) + cw.w = endGrpXMap.get(cw.cc.getHorizontal().getEndGroup()).intValue() - cw.x; + if (cw.cc.getVertical().getEndGroup() != null) + cw.h = endGrpYMap.get(cw.cc.getVertical().getEndGroup()).intValue() - cw.y; + + cw.x += bounds[0]; + cw.y += bounds[1]; + layoutAgain = cw.transferBounds(checkPrefChange && !layoutAgain); + + if (callbackList != null) { + for (int cb = 0; cb < callbackList.size(); cb++) + callbackList.get(cb).correctBounds(cw.comp); + } + } + } + } + clearGroupLinkBounds(); + if (++count > ((compCount << 3) + 10)) { + System.err.println("Unstable Cyclic Dependency in absolute-linked values!"); + break; + } + + } while (doAgain); + } + } + + // Add debug shapes for the "cells". Use the CompWraps as base for inding the cells. + if (debug) { + Collection<Cell> cwColl = grid.values(); + for (Iterator<Cell> it = cwColl.iterator(); it.hasNext();) { + ArrayList<CompWrap> compWraps = it.next().compWraps; + for (int i = 0, iSz = compWraps.size(); i < iSz; i++) { + CompWrap cw = compWraps.get(i); + LinkedDimGroup hGrp = getGroupContaining(colGroupLists, cw); + LinkedDimGroup vGrp = getGroupContaining(rowGroupLists, cw); + + if (hGrp != null && vGrp != null) + debugRects.add(new int[] {hGrp.lStart + bounds[0] - (hGrp.fromEnd ? hGrp.lSize : 0), vGrp.lStart + bounds[1] - (vGrp.fromEnd ? vGrp.lSize : 0), hGrp.lSize, vGrp.lSize}); + } + } + } + return layoutAgain; + } + + public void paintDebug() + { + if (debugRects != null) { + container.paintDebugOutline(); + + ArrayList<int[]> painted = new ArrayList<int[]>(); + for (int i = 0, iSz = debugRects.size(); i < iSz; i++) { + int[] r = debugRects.get(i); + if (painted.contains(r) == false) { + container.paintDebugCell(r[0], r[1], r[2], r[3]); + painted.add(r); + } + } + + for (Iterator<Cell> it = grid.values().iterator(); it.hasNext();) { + ArrayList<CompWrap> compWraps = it.next().compWraps; + for (int i = 0, iSz = compWraps.size(); i < iSz; i++) + compWraps.get(i).comp.paintDebugOutline(); + } + } + } + + public final int[] getWidth() + { + checkSizeCalcs(); + return width; + } + + public final int[] getHeight() + { + checkSizeCalcs(); + return height; + } + + private void checkSizeCalcs() + { + if (colFlowSpecs == null) { + colFlowSpecs = calcRowsOrColsSizes(colGroupLists, growXs, container.getWidth(), true); + rowFlowSpecs = calcRowsOrColsSizes(rowGroupLists, growYs, container.getHeight(), false); + + width = getMinPrefMaxSumSize(colFlowSpecs.sizes); + height = getMinPrefMaxSumSize(rowFlowSpecs.sizes); + + resetLinkValues(false); + + adjustSizeForAbsolute(width, true); + adjustSizeForAbsolute(height, false); + } + } + + private final UnitValue[] getPos(ComponentWrapper cw, CC cc) + { + UnitValue[] cbPos = null; + if (callbackList != null) { + for (int i = 0; i < callbackList.size() && cbPos == null; i++) + cbPos = callbackList.get(i).getPosition(cw); // NOT a copy! + } + + // If one is null, return the other (which many also be null) + UnitValue[] ccPos = cc.getPos(); // A copy!! + if (cbPos == null || ccPos == null) + return cbPos != null ? cbPos : ccPos; + + // Merge + for (int i = 0; i < 4; i++) { + UnitValue cbUv = cbPos[i]; + if (cbUv != null) + ccPos[i] = cbUv; + } + + return ccPos; + } + private final BoundSize[] getCallbackSize(ComponentWrapper cw, CC cc) + { + if (callbackList != null) { + for (int i = 0; i < callbackList.size(); i++) { + BoundSize[] bs = callbackList.get(i).getSize(cw); // NOT a copy! + if (bs != null) + return bs; + } + } + return null; + } + + private final int getDockInsets(TreeSet<Integer> set) + { + int c = 0; + for (Iterator<Integer> it = set.iterator(); it.hasNext();) { + if (it.next().intValue() < -MAX_GRID) { + c++; + } else { + break; // Since they are sorted we can break + } + } + return c; + } + + /** + * @param cw Never <code>null</code>. + * @param fc Never <code>null</code>. + * @param external The bounds should be stored even if they are not in {@link #linkTargetIDs}. + * @return IF a change has been done. + */ + private boolean setLinkedBounds(ComponentWrapper cw, CC fc, int x, int y, int w, int h, boolean external) + { + String id = fc.getId() != null ? fc.getId() : cw.getLinkId(); + if (id == null) + return false; + + String gid = null; + int grIx = id.indexOf('.'); + if (grIx != -1 ) { + gid = id.substring(0, grIx); + id = id.substring(grIx + 1); + } + + Object lay = container.getLayout(); + boolean changed = false; + if (external || (linkTargetIDs != null && linkTargetIDs.containsKey(id))) + changed = LinkHandler.setBounds(lay, id, x, y, w, h, !external, false); + + if (gid != null && (external || (linkTargetIDs != null && linkTargetIDs.containsKey(gid)))) { + if (linkTargetIDs == null) + linkTargetIDs = new HashMap<String, Boolean>(4); + + linkTargetIDs.put(gid, Boolean.TRUE); + changed |= LinkHandler.setBounds(lay, gid, x, y, w, h, !external, true); + } + + return changed; + } + + private void addLinkTargetIDs(UnitValue uv) + { + if (uv.isLinked()) { + if (linkTargetIDs == null) + linkTargetIDs = new HashMap<String, Boolean>(4); + + linkTargetIDs.put(uv.getLinkTargetId(), null); + } else { + for (int i = uv.getSubUnitCount() - 1; i >= 0; i--) { + UnitValue subUv = uv.getSubUnitValue(i); + if (subUv.isLinkedDeep()) + addLinkTargetIDs(subUv); + } + } + } + + /** Go to next cell. + * @param p The point to increase + * @param cnt How many cells to advance. + * @return The new value in the "incresing" dimension. + */ + private final int increase(int[] p, int cnt) + { + return lc.isFlowX() ? (p[0] += cnt) : (p[1] += cnt); + } + + /** Wraps to the next row or column depending on if horizontal flow or vertical flow is used. + * @param p The point to wrap and thus set either x or y to 0 and increase the other one. + * @param gapSize The gaps size specified in a "wrap XXX" or "newline XXX" or <code>null</code> if none. + * @param isWrap If gapSize is from a "wrap" (true) or "newline" (false). + */ + private final void wrap(int[] p, BoundSize gapSize, boolean isWrap) + { + boolean flowx = lc.isFlowX(); + p[0] = flowx ? 0 : p[0] + 1; + p[1] = flowx ? p[1] + 1 : 0; + + if (gapSize != null) { + if (wrapGapMap == null) + wrapGapMap = new HashMap<Integer, BoundSize>(8); + int ix = p[flowx ? 1 : 0]; + if (isWrap == false) + ix--; // newline. Use index before increment. + wrapGapMap.put(new Integer(ix), gapSize); + + // add the row/column so that the gap in the last row/col will not be removed. + if (flowx) { + rowIndexes.add(new Integer(p[1])); + } else { + colIndexes.add(new Integer(p[0])); + } + } + } + + /** Sort components (normally buttons in a button bar) so they appear in the correct order. + * @param cells The cells to sort. + * @param parent The parent. + */ + private static void sortCellsByPlatform(Collection<Cell> cells, ContainerWrapper parent) + { + String order = PlatformDefaults.getButtonOrder(); + String orderLo = order.toLowerCase(); + + int unrelSize = PlatformDefaults.convertToPixels(1, "u", true, 0, parent, null); + + if (unrelSize == UnitConverter.UNABLE) + throw new IllegalArgumentException("'unrelated' not recognized by PlatformDefaults!"); + + int[] gapUnrel = new int[] {unrelSize, unrelSize, LayoutUtil.NOT_SET}; + int[] flGap = new int[] {0, 0, LayoutUtil.NOT_SET}; + + for (Iterator<Cell> it = cells.iterator(); it.hasNext();) { + Cell cell = it.next(); + if (cell.hasTagged == false) + continue; + + CompWrap prevCW = null; + boolean nextUnrel = false; + boolean nextPush = false; + ArrayList<CompWrap> sortedList = new ArrayList<CompWrap>(cell.compWraps.size()); + + for (int i = 0, iSz = orderLo.length(); i < iSz; i++) { + char c = orderLo.charAt(i); + if (c == '+' || c == '_') { + nextUnrel = true; + if (c == '+') + nextPush = true; + } else { + String tag = PlatformDefaults.getTagForChar(c); + if (tag != null) { + for (int j = 0, jSz = cell.compWraps.size(); j < jSz; j++) { + CompWrap cw = cell.compWraps.get(j); + if (tag.equals(cw.cc.getTag())) { + if (Character.isUpperCase(order.charAt(i))) { + int min = PlatformDefaults.getMinimumButtonWidth().getPixels(0, parent, cw.comp); + if (min > cw.horSizes[LayoutUtil.MIN]) + cw.horSizes[LayoutUtil.MIN] = min; + + correctMinMax(cw.horSizes); + } + + sortedList.add(cw); + + if (nextUnrel) { + (prevCW != null ? prevCW : cw).mergeGapSizes(gapUnrel, cell.flowx, prevCW == null); + if (nextPush) { + cw.forcedPushGaps = 1; + nextUnrel = false; + nextPush = false; + } + } + + // "unknown" components will always get an Unrelated gap. + if (c == 'u') + nextUnrel = true; + prevCW = cw; + } + } + } + } + } + + // If we have a gap that was supposed to push but no more components was found to but the "gap before" then compensate. + if (sortedList.size() > 0) { + CompWrap cw = sortedList.get(sortedList.size() - 1); + if (nextUnrel) { + cw.mergeGapSizes(gapUnrel, cell.flowx, false); + if (nextPush) + cw.forcedPushGaps |= 2; + } + + // Remove first and last gap if not set explicitly. + if (cw.cc.getHorizontal().getGapAfter() == null) + cw.setGaps(flGap, 3); + + cw = sortedList.get(0); + if (cw.cc.getHorizontal().getGapBefore() == null) + cw.setGaps(flGap, 1); + } + + // Exchange the unsorted CompWraps for the sorted one. + if (cell.compWraps.size() == sortedList.size()) { + cell.compWraps.clear(); + } else { + cell.compWraps.removeAll(sortedList); + } + cell.compWraps.addAll(sortedList); + } + } + + private Float[] getDefaultGrowWeights(boolean hasPush, boolean isRows) + { + if (hasPush == false && (isRows ? lc.isFillY() : lc.isFillX()) == false) + return null; + + ArrayList<LinkedDimGroup>[] groupLists = isRows ? rowGroupLists : colGroupLists; + + Float[] gwArr = GROW_100; // Only create specific if any of the components have grow. + for (int i = 0, ix = 1; i < groupLists.length; i++, ix += 2) { + ArrayList<LinkedDimGroup> grps = groupLists[i]; + Float rowGw = null; + for (int j = 0; j < grps.size(); j++) { + LinkedDimGroup grp = grps.get(j); + + for (int c = 0; c < grp._compWraps.size(); c++) { + CompWrap cw = grp._compWraps.get(c); + Float gw = hasPush ? (isRows ? cw.cc.getPushY() : cw.cc.getPushX()) : (isRows ? cw.cc.getVertical() : cw.cc.getHorizontal()).getGrow(); + if (rowGw == null || (gw != null && gw.floatValue() > rowGw.floatValue())) + rowGw = gw; + } + } + + if (rowGw != null) { + if (gwArr == GROW_100) + gwArr = new Float[(groupLists.length << 1) + 1]; + gwArr[ix] = rowGw; + } + } + + return gwArr; + } + + private void clearGroupLinkBounds() + { + if (linkTargetIDs == null) + return; + + for (Iterator<Map.Entry<String,Boolean>> it = linkTargetIDs.entrySet().iterator(); it.hasNext();) { + Map.Entry<String, Boolean> o = it.next(); + if (o.getValue() == Boolean.TRUE) + LinkHandler.clearBounds(container.getLayout(), o.getKey()); + } + } + + private void resetLinkValues(boolean parentSize) + { + Object lay = container.getLayout(); + LinkHandler.clearTemporaryBounds(lay); + + boolean defIns = !hasDocks(); + + int parW = parentSize ? container.getWidth() : 0; + int parH = parentSize ? container.getHeight() : 0; + int insX = LayoutUtil.getInsets(lc, 0, defIns).getPixels(0, container, null); + int insY = LayoutUtil.getInsets(lc, 1, defIns).getPixels(0, container, null); + int insW = parW - insX - LayoutUtil.getInsets(lc, 2, defIns).getPixels(0, container, null); + int insH = parH - insY - LayoutUtil.getInsets(lc, 3, defIns).getPixels(0, container, null); + + LinkHandler.setBounds(lay, "visual", insX, insY, insW, insH, true, false); + LinkHandler.setBounds(lay, "container", 0, 0, parW, parH, true, false); + } + + /** Returns the {@link net.miginfocom.layout.Grid.LinkedDimGroup} that has the {@link net.miginfocom.layout.Grid.CompWrap} + * <code>cw</code>. + * @param groupLists The lists to search in. + * @param cw The component wrap to find. + * @return The linked group or <code>null</code> if none had the component wrap. + */ + private static LinkedDimGroup getGroupContaining(ArrayList<LinkedDimGroup>[] groupLists, CompWrap cw) + { + for (int i = 0; i < groupLists.length; i++) { + ArrayList<LinkedDimGroup> groups = groupLists[i]; + for (int j = 0, jSz = groups.size(); j < jSz; j++) { + ArrayList<CompWrap> cwList = groups.get(j)._compWraps; + for (int k = 0, kSz = cwList.size(); k < kSz; k++) { + if (cwList.get(k) == cw) + return groups.get(j); + } + } + } + return null; + } + + private boolean doAbsoluteCorrections(CompWrap cw, int[] bounds) + { + boolean changed = false; + + int[] stSz = getAbsoluteDimBounds(cw, bounds[2], true); + if (stSz != null) + cw.setDimBounds(stSz[0], stSz[1], true); + + stSz = getAbsoluteDimBounds(cw, bounds[3], false); + if (stSz != null) + cw.setDimBounds(stSz[0], stSz[1], false); + + // If there is a link id, store the new bounds. + if (linkTargetIDs != null) + changed = setLinkedBounds(cw.comp, cw.cc, cw.x, cw.y, cw.w, cw.h, false); + + return changed; + } + + private void adjustSizeForAbsolute(int[] curSizes, boolean isHor) + { + Cell absCell = grid.get(null); + if (absCell == null || absCell.compWraps.size() == 0) + return; + + ArrayList<CompWrap> cws = absCell.compWraps; + + int maxEnd = 0; + for (int j = 0, cwSz = absCell.compWraps.size(); j < cwSz + 3; j++) { // "Do Again" max absCell.compWraps.size() + 3 times. + boolean doAgain = false; + for (int i = 0; i < cwSz; i++) { + CompWrap cw = cws.get(i); + int[] stSz = getAbsoluteDimBounds(cw, 0, isHor); + int end = stSz[0] + stSz[1]; + if (maxEnd < end) + maxEnd = end; + + // If there is a link id, store the new bounds. + if (linkTargetIDs != null) + doAgain |= setLinkedBounds(cw.comp, cw.cc, stSz[0], stSz[0], stSz[1], stSz[1], false); + } + if (doAgain == false) + break; + + // We need to check this again since the coords may be smaller this round. + maxEnd = 0; + clearGroupLinkBounds(); + } + + maxEnd += LayoutUtil.getInsets(lc, isHor ? 3 : 2, !hasDocks()).getPixels(0, container, null); + + if (curSizes[LayoutUtil.MIN] < maxEnd) + curSizes[LayoutUtil.MIN] = maxEnd; + if (curSizes[LayoutUtil.PREF] < maxEnd) + curSizes[LayoutUtil.PREF] = maxEnd; + } + + private int[] getAbsoluteDimBounds(CompWrap cw, int refSize, boolean isHor) + { + if (cw.cc.isExternal()) { + if (isHor) { + return new int[] {cw.comp.getX(), cw.comp.getWidth()}; + } else { + return new int[] {cw.comp.getY(), cw.comp.getHeight()}; + } + } + + int[] plafPad = lc.isVisualPadding() ? cw.comp.getVisualPadding() : null; + UnitValue[] pad = cw.cc.getPadding(); + + // If no changes do not create a lot of objects + if (cw.pos == null && plafPad == null && pad == null) + return null; + + // Set start + int st = isHor ? cw.x : cw.y; + int sz = isHor ? cw.w : cw.h; + + // If absolute, use those coordinates instead. + if (cw.pos != null) { + UnitValue stUV = cw.pos != null ? cw.pos[isHor ? 0 : 1] : null; + UnitValue endUV = cw.pos != null ? cw.pos[isHor ? 2 : 3] : null; + + int minSz = cw.getSize(LayoutUtil.MIN, isHor); + int maxSz = cw.getSize(LayoutUtil.MAX, isHor); + sz = Math.min(Math.max(cw.getSize(LayoutUtil.PREF, isHor), minSz), maxSz); + + if (stUV != null) { + st = stUV.getPixels(stUV.getUnit() == UnitValue.ALIGN ? sz : refSize, container, cw.comp); + + if (endUV != null) // if (endUV == null && cw.cc.isBoundsIsGrid() == true) + sz = Math.min(Math.max((isHor ? (cw.x + cw.w) : (cw.y + cw.h)) - st, minSz), maxSz); + } + + if (endUV != null) { + if (stUV != null) { // if (stUV != null || cw.cc.isBoundsIsGrid()) { + sz = Math.min(Math.max(endUV.getPixels(refSize, container, cw.comp) - st, minSz), maxSz); + } else { + st = endUV.getPixels(refSize, container, cw.comp) - sz; + } + } + } + + // If constraint has padding -> correct the start/size + if (pad != null) { + UnitValue uv = pad[isHor ? 1 : 0]; + int p = uv != null ? uv.getPixels(refSize, container, cw.comp) : 0; + st += p; + uv = pad[isHor ? 3 : 2]; + sz += -p + (uv != null ? uv.getPixels(refSize, container, cw.comp) : 0); + } + + // If the plaf converter has padding -> correct the start/size + if (plafPad != null) { + int p = plafPad[isHor ? 1 : 0]; + st += p; + sz += -p + (plafPad[isHor ? 3 : 2]); + } + + return new int[] {st, sz}; + } + + private void layoutInOneDim(int refSize, UnitValue align, boolean isRows, Float[] defaultGrowW) + { + boolean fromEnd = !(isRows ? lc.isTopToBottom() : LayoutUtil.isLeftToRight(lc, container)); + DimConstraint[] primDCs = (isRows ? rowConstr : colConstr).getConstaints(); + FlowSizeSpec fss = isRows ? rowFlowSpecs : colFlowSpecs; + ArrayList<LinkedDimGroup>[] rowCols = isRows ? rowGroupLists : colGroupLists; + + int[] rowColSizes = LayoutUtil.calculateSerial(fss.sizes, fss.resConstsInclGaps, defaultGrowW, LayoutUtil.PREF, refSize); + + if (LayoutUtil.isDesignTime(container)) { + TreeSet<Integer> indexes = isRows ? rowIndexes : colIndexes; + int[] ixArr = new int[indexes.size()]; + int ix = 0; + for (Integer i : indexes) + ixArr[ix++] = i.intValue(); + + putSizesAndIndexes(container.getComponent(), rowColSizes, ixArr, isRows); + } + + int curPos = align != null ? Math.round(align.getPixels(refSize - LayoutUtil.sum(rowColSizes), container, null)) : 0; + + if (fromEnd) + curPos = refSize - curPos; + + for (int i = 0 ; i < rowCols.length; i++) { + ArrayList<LinkedDimGroup> linkedGroups = rowCols[i]; + int scIx = i - (isRows ? dockOffY : dockOffX); + + int bIx = i << 1; + int bIx2 = bIx + 1; + + curPos += (fromEnd ? -rowColSizes[bIx] : rowColSizes[bIx]); + + DimConstraint primDC = scIx >= 0 ? primDCs[scIx >= primDCs.length ? primDCs.length - 1 : scIx] : DOCK_DIM_CONSTRAINT; + + int rowSize = rowColSizes[bIx2]; + + for (int j = 0; j < linkedGroups.size(); j++) { + LinkedDimGroup group = linkedGroups.get(j); + int groupSize = rowSize; + if (group.span > 1) + groupSize = LayoutUtil.sum(rowColSizes, bIx2, Math.min((group.span << 1) - 1, rowColSizes.length - bIx2 - 1)); + + group.layout(primDC, curPos, groupSize, group.span); + } + + curPos += (fromEnd ? -rowSize : rowSize); + } + } + + private void addToSizeGroup(HashMap<String, int[]> sizeGroups, String sizeGroup, int[] size) + { + if (sizeGroups == null) + return; + + int[] sgSize = sizeGroups.get(sizeGroup); + if (sgSize == null) { + sizeGroups.put(sizeGroup, new int[] {size[LayoutUtil.MIN], size[LayoutUtil.PREF], size[LayoutUtil.MAX]}); + } else { + sgSize[LayoutUtil.MIN] = Math.max(size[LayoutUtil.MIN], sgSize[LayoutUtil.MIN]); + sgSize[LayoutUtil.PREF] = Math.max(size[LayoutUtil.PREF], sgSize[LayoutUtil.PREF]); + sgSize[LayoutUtil.MAX] = Math.min(size[LayoutUtil.MAX], sgSize[LayoutUtil.MAX]); + } + } + + private HashMap<String, Integer> addToEndGroup(HashMap<String, Integer> endGroups, String endGroup, int end) + { + if (endGroup != null) { + if (endGroups == null) + endGroups = new HashMap<String, Integer>(2); + + Integer oldEnd = endGroups.get(endGroup); + if (oldEnd == null || end > oldEnd.intValue()) + endGroups.put(endGroup, new Integer(end)); + } + return endGroups; + } + + /** Calculates Min, Preferred and Max size for the columns OR rows. + * @param defGrow The default grow weight if the specs does not have anyone that will grow. Comes from "push" in the CC. + * @return The sizes in a {@link net.miginfocom.layout.Grid.FlowSizeSpec}. + */ + private FlowSizeSpec calcRowsOrColsSizes(ArrayList<LinkedDimGroup>[] groupsLists, Float[] defGrow, int refSize, boolean isHor) + { + DimConstraint[] primDCs = (isHor? colConstr : rowConstr).getConstaints(); + TreeSet<Integer> primIdexes = isHor ? colIndexes : rowIndexes; + + int[][] rowColBoundSizes = new int[primIdexes.size()][]; + HashMap<String, int[]> sizeGroupMap = new HashMap<String, int[]>(2); + DimConstraint[] allDCs = new DimConstraint[primIdexes.size()]; + + Iterator<Integer> primIt = primIdexes.iterator(); + for (int r = 0; r < rowColBoundSizes.length; r++) { + int cellIx = primIt.next().intValue(); + int[] rowColSizes = new int[3]; + + if (cellIx >= -MAX_GRID && cellIx <= MAX_GRID) { // If not dock cell + allDCs[r] = primDCs[cellIx >= primDCs.length ? primDCs.length - 1 : cellIx]; + } else { + allDCs[r] = DOCK_DIM_CONSTRAINT; + } + + ArrayList<LinkedDimGroup> groups = groupsLists[r]; + + int[] groupSizes = new int[] { + getTotalGroupsSizeParallel(groups, LayoutUtil.MIN, false), + getTotalGroupsSizeParallel(groups, LayoutUtil.PREF, false), + LayoutUtil.INF}; + + correctMinMax(groupSizes); + BoundSize dimSize = allDCs[r].getSize(); + + for (int sType = LayoutUtil.MIN; sType <= LayoutUtil.MAX; sType++) { + + int rowColSize = groupSizes[sType]; + + UnitValue uv = dimSize != null ? dimSize.getSize(sType) : null; + if (uv != null) { + // If the size of the column is a link to some other size, use that instead + int unit = uv.getUnit(); + if (unit == UnitValue.PREF_SIZE) { + rowColSize = groupSizes[LayoutUtil.PREF]; + } else if (unit == UnitValue.MIN_SIZE) { + rowColSize = groupSizes[LayoutUtil.MIN]; + } else if (unit == UnitValue.MAX_SIZE) { + rowColSize = groupSizes[LayoutUtil.MAX]; + } else { + rowColSize = uv.getPixels(refSize, container, null); + } + } else if (cellIx >= -MAX_GRID && cellIx <= MAX_GRID && rowColSize == 0) { + rowColSize = LayoutUtil.isDesignTime(container) ? LayoutUtil.getDesignTimeEmptySize() : 0; // Empty rows with no size set gets XX pixels if design time + } + + rowColSizes[sType] = rowColSize; + } + + correctMinMax(rowColSizes); + addToSizeGroup(sizeGroupMap, allDCs[r].getSizeGroup(), rowColSizes); + + rowColBoundSizes[r] = rowColSizes; + } + + // Set/equalize the size groups to same the values. + if (sizeGroupMap.size() > 0) { + for (int r = 0; r < rowColBoundSizes.length; r++) { + if (allDCs[r].getSizeGroup() != null) + rowColBoundSizes[r] = sizeGroupMap.get(allDCs[r].getSizeGroup()); + } + } + + // Add the gaps + ResizeConstraint[] resConstrs = getRowResizeConstraints(allDCs); + + boolean[] fillInPushGaps = new boolean[allDCs.length + 1]; + int[][] gapSizes = getRowGaps(allDCs, refSize, isHor, fillInPushGaps); + + + FlowSizeSpec fss = mergeSizesGapsAndResConstrs(resConstrs, fillInPushGaps, rowColBoundSizes, gapSizes, refSize, container); + + // Spanning components are not handled yet. Check and adjust the multi-row min/pref they enforce. + adjustMinPrefForSpanningComps(allDCs, defGrow, fss, groupsLists); + + return fss; + } + + private static int[] getMinPrefMaxSumSize(int[][] sizes) + { + int[] retSizes = new int[3]; + + for (int i = 0; i < sizes.length; i++) { + if (sizes[i] != null) { + int[] size = sizes[i]; + for (int sType = LayoutUtil.MIN; sType <= LayoutUtil.MAX; sType++) { + int s = size[sType]; + + if (s != LayoutUtil.NOT_SET) { + if (sType == LayoutUtil.PREF) { + int bnd = size[LayoutUtil.MAX]; + if (bnd != LayoutUtil.NOT_SET && bnd < s) + s = bnd; + + bnd = size[LayoutUtil.MIN]; + if (bnd > s) // Includes s == LayoutUtil.NOT_SET since < 0. + s = bnd; + } + + retSizes[sType] += s; // MAX compensated below. + } + } + + // So that MAX is always correct. + if (size[LayoutUtil.MAX] == LayoutUtil.NOT_SET) + retSizes[LayoutUtil.MAX] = LayoutUtil.INF; + } + } + + return retSizes; + } + + private static ResizeConstraint[] getRowResizeConstraints(DimConstraint[] specs) + { + ResizeConstraint[] resConsts = new ResizeConstraint[specs.length]; + for (int i = 0; i < resConsts.length; i++) + resConsts[i] = specs[i].resize; + return resConsts; + } + + private static ResizeConstraint[] getComponentResizeConstraints(ArrayList<CompWrap> compWraps, boolean isHor) + { + ResizeConstraint[] resConsts = new ResizeConstraint[compWraps.size()]; + for (int i = 0; i < resConsts.length; i++) { + CC fc = compWraps.get(i).cc; + resConsts[i] = fc.getDimConstraint(isHor).resize; + + // Always grow docking components in the correct dimension. + int dock = fc.getDockSide(); + if (isHor ? (dock == 0 || dock == 2) : (dock == 1 || dock == 3)) { + ResizeConstraint dc = resConsts[i]; + resConsts[i] = new ResizeConstraint(dc.shrinkPrio, dc.shrink, dc.growPrio, ResizeConstraint.WEIGHT_100); + } + } + return resConsts; + } + + private static boolean[] getComponentGapPush(ArrayList<CompWrap> compWraps, boolean isHor) + { + // Make one element bigger and or the after gap with the next before gap. + boolean[] barr = new boolean[compWraps.size() + 1]; + for (int i = 0; i < barr.length; i++) { + + boolean push = i > 0 ? compWraps.get(i - 1).isPushGap(isHor, false) : false; + + if (push == false && i < (barr.length - 1)) + push = compWraps.get(i).isPushGap(isHor, true); + + barr[i] = push; + } + return barr; + } + + /** Returns the row gaps in pixel sizes. One more than there are <code>specs</code> sent in. + * @param specs + * @param refSize + * @param isHor + * @param fillInPushGaps If the gaps are pushing. <b>NOTE!</b> this argument will be filled in and thus changed! + * @return The row gaps in pixel sizes. One more than there are <code>specs</code> sent in. + */ + private int[][] getRowGaps(DimConstraint[] specs, int refSize, boolean isHor, boolean[] fillInPushGaps) + { + BoundSize defGap = isHor ? lc.getGridGapX() : lc.getGridGapY(); + if (defGap == null) + defGap = isHor ? PlatformDefaults.getGridGapX() : PlatformDefaults.getGridGapY(); + int[] defGapArr = defGap.getPixelSizes(refSize, container, null); + + boolean defIns = !hasDocks(); + + UnitValue firstGap = LayoutUtil.getInsets(lc, isHor ? 1 : 0, defIns); + UnitValue lastGap = LayoutUtil.getInsets(lc, isHor ? 3 : 2, defIns); + + int[][] retValues = new int[specs.length + 1][]; + + for (int i = 0, wgIx = 0; i < retValues.length; i++) { + DimConstraint specBefore = i > 0 ? specs[i - 1] : null; + DimConstraint specAfter = i < specs.length ? specs[i] : null; + + // No gap if between docking components. + boolean edgeBefore = (specBefore == DOCK_DIM_CONSTRAINT || specBefore == null); + boolean edgeAfter = (specAfter == DOCK_DIM_CONSTRAINT || specAfter == null); + if (edgeBefore && edgeAfter) + continue; + + BoundSize wrapGapSize = (wrapGapMap == null || isHor == lc.isFlowX() ? null : wrapGapMap.get(new Integer(wgIx++))); + + if (wrapGapSize == null) { + + int[] gapBefore = specBefore != null ? specBefore.getRowGaps(container, null, refSize, false) : null; + int[] gapAfter = specAfter != null ? specAfter.getRowGaps(container, null, refSize, true) : null; + + if (edgeBefore && gapAfter == null && firstGap != null) { + + int bef = firstGap.getPixels(refSize, container, null); + retValues[i] = new int[] {bef, bef, bef}; + + } else if (edgeAfter && gapBefore == null && firstGap != null) { + + int aft = lastGap.getPixels(refSize, container, null); + retValues[i] = new int[] {aft, aft, aft}; + + } else { + retValues[i] = gapAfter != gapBefore ? mergeSizes(gapAfter, gapBefore) : new int[] {defGapArr[0], defGapArr[1], defGapArr[2]}; + } + + if (specBefore != null && specBefore.isGapAfterPush() || specAfter != null && specAfter.isGapBeforePush()) + fillInPushGaps[i] = true; + } else { + + if (wrapGapSize.isUnset()) { + retValues[i] = new int[] {defGapArr[0], defGapArr[1], defGapArr[2]}; + } else { + retValues[i] = wrapGapSize.getPixelSizes(refSize, container, null); + } + fillInPushGaps[i] = wrapGapSize.getGapPush(); + } + } + return retValues; + } + + private static int[][] getGaps(ArrayList<CompWrap> compWraps, boolean isHor) + { + int compCount = compWraps.size(); + int[][] retValues = new int[compCount + 1][]; + + retValues[0] = compWraps.get(0).getGaps(isHor, true); + for (int i = 0; i < compCount; i++) { + int[] gap1 = compWraps.get(i).getGaps(isHor, false); + int[] gap2 = i < compCount - 1 ? compWraps.get(i + 1).getGaps(isHor, true) : null; + + retValues[i + 1] = mergeSizes(gap1, gap2); + } + + return retValues; + } + + private boolean hasDocks() + { + return (dockOffX > 0 || dockOffY > 0 || rowIndexes.last() > MAX_GRID || colIndexes.last() > MAX_GRID); + } + + /** + * @param specs The specs for the columns or rows. Last index will be used of <code>count</code> is greater than this array's length. + * @param defGrow The default grow weight if the specs does not have anyone that will grow. Comes from "push" in the CC. + * @param fss + * @param groupsLists + */ + private void adjustMinPrefForSpanningComps(DimConstraint[] specs, Float[] defGrow, FlowSizeSpec fss, ArrayList<LinkedDimGroup>[] groupsLists) + { + for (int r = 0; r < groupsLists.length; r++) { + ArrayList<LinkedDimGroup> groups = groupsLists[r]; + + for (int i = 0; i < groups.size(); i++) { + LinkedDimGroup group = groups.get(i); + if (group.span == 1) + continue; + + int cSize = group.getMinPrefMax()[LayoutUtil.PREF]; + if (cSize == LayoutUtil.NOT_SET) + continue; + + int rowSize = 0; + int sIx = (r << 1) + 1; + int len = Math.min((group.span << 1), fss.sizes.length - sIx) - 1; + for (int j = sIx; j < sIx + len; j++) { + int sz = fss.sizes[j][LayoutUtil.PREF]; + if (sz != LayoutUtil.NOT_SET) + rowSize += sz; + } + + if (rowSize < cSize) { + for (int eag = 0, newRowSize = 0; eag < 4 && newRowSize < cSize; eag++) + newRowSize = fss.expandSizes(specs, defGrow, cSize, sIx, len, LayoutUtil.PREF, eag); + } + } + } + } + + /** For one dimension divide the component wraps into logical groups. One group for component wraps that share a common something, + * line the property to layout by base line. + * @param isRows If rows, and not columns, are to be divided. + * @return One <code>ArrayList<LinkedDimGroup></code> for every row/column. + */ + private ArrayList<LinkedDimGroup>[] divideIntoLinkedGroups(boolean isRows) + { + boolean fromEnd = !(isRows ? lc.isTopToBottom() : LayoutUtil.isLeftToRight(lc, container)); + TreeSet<Integer> primIndexes = isRows ? rowIndexes : colIndexes; + TreeSet<Integer> secIndexes = isRows ? colIndexes : rowIndexes; + DimConstraint[] primDCs = (isRows ? rowConstr : colConstr).getConstaints(); + + ArrayList<LinkedDimGroup>[] groupLists = new ArrayList[primIndexes.size()]; + + int gIx = 0; + for (Iterator<Integer> primIt = primIndexes.iterator(); primIt.hasNext();) { + int i = primIt.next().intValue(); + + DimConstraint dc; + if (i >= -MAX_GRID && i <= MAX_GRID) { // If not dock cell + dc = primDCs[i >= primDCs.length ? primDCs.length - 1 : i]; + } else { + dc = DOCK_DIM_CONSTRAINT; + } + + ArrayList<LinkedDimGroup> groupList = new ArrayList<LinkedDimGroup>(2); + groupLists[gIx++] = groupList; + + for (Iterator<Integer> secIt = secIndexes.iterator(); secIt.hasNext();) { + int j = secIt.next().intValue(); + Cell cell = isRows ? getCell(i, j) : getCell(j, i); + if (cell == null || cell.compWraps.size() == 0) + continue; + + int span = (isRows ? cell.spany : cell.spanx); + if (span > 1) + span = convertSpanToSparseGrid(i, span, primIndexes); + + boolean isPar = cell.flowx == isRows; + + if ((isPar == false && cell.compWraps.size() > 1) || span > 1) { + + int linkType = isPar ? LinkedDimGroup.TYPE_PARALLEL : LinkedDimGroup.TYPE_SERIAL; + LinkedDimGroup lg = new LinkedDimGroup("p," + j, span, linkType, !isRows, fromEnd); + lg.setCompWraps(cell.compWraps); + groupList.add(lg); + } else { + for (int cwIx = 0; cwIx < cell.compWraps.size(); cwIx++) { + CompWrap cw = cell.compWraps.get(cwIx); + boolean rowBaselineAlign = (isRows && dc.getAlignOrDefault(!isRows) == UnitValue.BASELINE_IDENTITY); + + String linkCtx = cw.getLinkContext(rowBaselineAlign); + + // Find a group with same link context and put it in that group. + boolean foundList = false; + for (int glIx = 0, lastGl = groupList.size() - 1; glIx <= lastGl ; glIx++) { + LinkedDimGroup group = groupList.get(glIx); + if (group.linkCtx == linkCtx || linkCtx != null && linkCtx.equals(group.linkCtx)) { + group.addCompWrap(cw); + foundList = true; + break; + } + } + + // If none found and at last add a new group. + if (foundList == false) { + + int linkType = LinkedDimGroup.TYPE_PARALLEL; + if (isRows && cw.isBaselineAlign(rowBaselineAlign)) + linkType = LinkedDimGroup.TYPE_BASELINE; + + LinkedDimGroup lg = new LinkedDimGroup(linkCtx, 1, linkType, !isRows, fromEnd); + lg.addCompWrap(cw); + groupList.add(lg); + } + } + } + } + } + return groupLists; + } + + /** Spanning is specified in the uncompressed grid number. They can for instance be more than 60000 for the outer + * edge dock grid cells. When the grid is compressed and indexed after only the cells that area occupied the span + * is erratic. This method use the row/col indexes and corrects the span to be correct for the compressed grid. + * @param span The span un the uncompressed grid. <code>LayoutUtil.INF</code> will be interpreted to span the rest + * of the column/row excluding the surrounding docking components. + * @param indexes The indexes in the correct dimension. + * @return The converted span. + */ + private int convertSpanToSparseGrid(int curIx, int span, TreeSet<Integer> indexes) + { + int lastIx = curIx + span; + int retSpan = 1; + + for (Iterator<Integer> it = indexes.iterator(); it.hasNext();) { + int ix = it.next(); + if (ix <= curIx) + continue; // We have not arrive to the correct index yet + + if (ix >= lastIx) + break; + + retSpan++; + } + return retSpan; + } + + private final boolean isCellFree(int r, int c, ArrayList<int[]> occupiedRects) + { + if (getCell(r, c) != null) + return false; + + for (int i = 0; i < occupiedRects.size(); i++) { + int[] rect = occupiedRects.get(i); + if (rect[0] <= c && rect[1] <= r && rect[0] + rect[2] > c && rect[1] + rect[3] > r) + return false; + } + return true; + } + + private Cell getCell(int r, int c) + { + return grid.get(new Integer((r << 16) + c)); + } + + private void setCell(int r, int c, Cell cell) + { + if (c < 0 || c > MAX_GRID || r < 0 || r > MAX_GRID) + throw new IllegalArgumentException("Cell position out of bounds. row: " + r + ", col: " + c); + + rowIndexes.add(new Integer(r)); + colIndexes.add(new Integer(c)); + + grid.put(new Integer((r << 16) + c), cell); + } + + /** Adds a docking cell. That cell is outside the normal cell indexes. + * @param dockInsets The current dock insets. Will be updated! + * @param side top == 0, left == 1, bottom = 2, right = 3. + * @param cw The compwrap to put in a cell and add. + */ + private void addDockingCell(int[] dockInsets, int side, CompWrap cw) + { + int r, c, spanx = 1, spany = 1; + switch (side) { + case 0: + case 2: + r = side == 0 ? dockInsets[0]++ : dockInsets[2]--; + c = dockInsets[1]; + spanx = dockInsets[3] - dockInsets[1] + 1; // The +1 is for cell 0. + colIndexes.add(new Integer(dockInsets[3])); // Make sure there is a receiving cell + break; + + case 1: + case 3: + c = side == 1 ? dockInsets[1]++ : dockInsets[3]--; + r = dockInsets[0]; + spany = dockInsets[2] - dockInsets[0] + 1; // The +1 is for cell 0. + rowIndexes.add(new Integer(dockInsets[2])); // Make sure there is a receiving cell + break; + + default: + throw new IllegalArgumentException("Internal error 123."); + } + + rowIndexes.add(new Integer(r)); + colIndexes.add(new Integer(c)); + + grid.put(new Integer((r << 16) + c), new Cell(cw, spanx, spany, spanx > 1)); + } + + /** A simple representation of a cell in the grid. Contains a number of component wraps and if they span more than one cell. + */ + private static class Cell + { + private final int spanx, spany; + private final boolean flowx; + private final ArrayList<CompWrap> compWraps = new ArrayList<CompWrap>(1); + + private boolean hasTagged = false; // If one or more components have styles and need to be checked by the component sorter + + private Cell(CompWrap cw) + { + this(cw, 1, 1, true); + } + + private Cell(int spanx, int spany, boolean flowx) + { + this(null, spanx, spany, flowx); + } + + private Cell(CompWrap cw, int spanx, int spany, boolean flowx) + { + if (cw != null) + compWraps.add(cw); + this.spanx = spanx; + this.spany = spany; + this.flowx = flowx; + } + } + + /** A number of component wraps that share a layout "something" <b>in one dimension</b> + */ + private static class LinkedDimGroup + { + private static final int TYPE_SERIAL = 0; + private static final int TYPE_PARALLEL = 1; + private static final int TYPE_BASELINE = 2; + + private final String linkCtx; + private final int span; + private final int linkType; + private final boolean isHor, fromEnd; + + private ArrayList<CompWrap> _compWraps = new ArrayList<CompWrap>(4); + + private int[] sizes = null; + private int lStart = 0, lSize = 0; // Currently mostly for debug painting + + private LinkedDimGroup(String linkCtx, int span, int linkType, boolean isHor, boolean fromEnd) + { + this.linkCtx = linkCtx; + this.span = span; + this.linkType = linkType; + this.isHor = isHor; + this.fromEnd = fromEnd; + } + + private void addCompWrap(CompWrap cw) + { + _compWraps.add(cw); + sizes = null; + } + + private void setCompWraps(ArrayList<CompWrap> cws) + { + if (_compWraps != cws) { + _compWraps = cws; + sizes = null; + } + } + + private void layout(DimConstraint dc, int start, int size, int spanCount) + { + lStart = start; + lSize = size; + + if (_compWraps.size() == 0) + return; + + ContainerWrapper parent = _compWraps.get(0).comp.getParent(); + if (linkType == TYPE_PARALLEL) { + layoutParallel(parent, _compWraps, dc, start, size, isHor, spanCount, fromEnd); + } else if (linkType == TYPE_BASELINE) { + layoutBaseline(parent, _compWraps, dc, start, size, LayoutUtil.PREF, spanCount); + } else { + layoutSerial(parent, _compWraps, dc, start, size, isHor, spanCount, fromEnd); + } + } + + /** Returns the min/pref/max sizes for this cell. Returned array <b>must not be altered</b> + * @return A shared min/pref/max array of sizes. Always of length 3 and never <code>null</code>. Will always be of type STATIC and PIXEL. + */ + private int[] getMinPrefMax() + { + if (sizes == null && _compWraps.size() > 0) { + sizes = new int[3]; + for (int sType = LayoutUtil.MIN; sType <= LayoutUtil.PREF; sType++) { + if (linkType == TYPE_PARALLEL) { + sizes[sType] = getTotalSizeParallel(_compWraps, sType, isHor); + } else if (linkType == TYPE_BASELINE) { + int[] aboveBelow = getBaselineAboveBelow(_compWraps, sType, false); + sizes[sType] = aboveBelow[0] + aboveBelow[1]; + } else { + sizes[sType] = getTotalSizeSerial(_compWraps, sType, isHor); + } + } + sizes[LayoutUtil.MAX] = LayoutUtil.INF; + } + return sizes; + } + } + + /** Wraps a {@link java.awt.Component} together with its constraint. Caches a lot of information about the component so + * for instance not the preferred size has to be calculated more than once. + */ + private final static class CompWrap + { + private final ComponentWrapper comp; + private final CC cc; + private final UnitValue[] pos; + private int[][] gaps; // [top,left(actually before),bottom,right(actually after)][min,pref,max] + + private final int[] horSizes = new int[3]; + private final int[] verSizes = new int[3]; + + private int x = LayoutUtil.NOT_SET, y = LayoutUtil.NOT_SET, w = LayoutUtil.NOT_SET, h = LayoutUtil.NOT_SET; + + private int forcedPushGaps = 0; // 1 == before, 2 = after. Bitwise. + + private CompWrap(ComponentWrapper c, CC cc, int eHideMode, UnitValue[] pos, BoundSize[] callbackSz) + { + this.comp = c; + this.cc = cc; + this.pos = pos; + + if (eHideMode <= 0) { + BoundSize hBS = (callbackSz != null && callbackSz[0] != null) ? callbackSz[0] : cc.getHorizontal().getSize(); + BoundSize vBS = (callbackSz != null && callbackSz[1] != null) ? callbackSz[1] : cc.getVertical().getSize(); + + for (int i = LayoutUtil.MIN; i <= LayoutUtil.MAX; i++) { + horSizes[i] = getSize(hBS, i, true); + verSizes[i] = getSize(vBS, i, false); + } + + correctMinMax(horSizes); + correctMinMax(verSizes); + } + + if (eHideMode > 1) { + gaps = new int[4][]; + for (int i = 0; i < gaps.length; i++) + gaps[i] = new int[3]; + } + } + + private final int getSize(BoundSize uvs, int sizeType, boolean isHor) + { + if (uvs == null || uvs.getSize(sizeType) == null) { + switch(sizeType) { + case LayoutUtil.MIN: + return isHor ? comp.getMinimumWidth() : comp.getMinimumHeight(); + case LayoutUtil.PREF: + return isHor ? comp.getPreferredWidth() : comp.getPreferredHeight(); + default: + return isHor ? comp.getMaximumWidth() : comp.getMaximumHeight(); + } + } + + ContainerWrapper par = comp.getParent(); + return uvs.getSize(sizeType).getPixels(isHor ? par.getWidth() : par.getHeight(), par, comp); + } + + private final void calcGaps(ComponentWrapper before, CC befCC, ComponentWrapper after, CC aftCC, String tag, boolean flowX, boolean isLTR) + { + ContainerWrapper par = comp.getParent(); + int parW = par.getWidth(); + int parH = par.getHeight(); + + BoundSize befGap = before != null ? (flowX ? befCC.getHorizontal() : befCC.getVertical()).getGapAfter() : null; + BoundSize aftGap = after != null ? (flowX ? aftCC.getHorizontal() : aftCC.getVertical()).getGapBefore() : null; + + mergeGapSizes(cc.getVertical().getComponentGaps(par, comp, befGap, (flowX ? null : before), tag, parH, 0, isLTR), false, true); + mergeGapSizes(cc.getHorizontal().getComponentGaps(par, comp, befGap, (flowX ? before : null), tag, parW, 1, isLTR), true, true); + mergeGapSizes(cc.getVertical().getComponentGaps(par, comp, aftGap, (flowX ? null : after), tag, parH, 2, isLTR), false, false); + mergeGapSizes(cc.getHorizontal().getComponentGaps(par, comp, aftGap, (flowX ? after : null), tag, parW, 3, isLTR), true, false); + } + + private final void setDimBounds(int start, int size, boolean isHor) + { + if (isHor) { + x = start; + w = size; + } else { + y = start; + h = size; + } + } + + private final boolean isPushGap(boolean isHor, boolean isBefore) + { + if (isHor && ((isBefore ? 1 : 2) & forcedPushGaps) != 0) + return true; // Forced + + DimConstraint dc = cc.getDimConstraint(isHor); + BoundSize s = isBefore ? dc.getGapBefore() : dc.getGapAfter(); + return s != null && s.getGapPush(); + } + + /** + * @return If the preferred size have changed because of the new bounds (needed for SWT only) + */ + private final boolean transferBounds(boolean checkPrefChange) + { + comp.setBounds(x, y, w, h); + + if (checkPrefChange && w != horSizes[LayoutUtil.PREF]) { + BoundSize vSz = cc.getVertical().getSize(); + if ((vSz == null || vSz.getPreferred() == null)) { + if (comp.getPreferredHeight() != verSizes[LayoutUtil.PREF]) { + //System.out.println(comp.getComponent() + "oldPrefH: " + verSizes[LayoutUtil.PREF] + ", new: " + comp.getPreferredHeight()); + return true; + } + } + } + + return false; + } + + private final void setSizes(int[] sizes, boolean isHor) + { + if (sizes == null) + return; + + int[] s = isHor ? horSizes : verSizes; + for (int i = 0; i < 3; i++) + s[i] = sizes[i]; + } + + private void setGaps(int[] minPrefMax, int ix) + { + if (gaps == null) + gaps = new int[][] {null, null, null, null}; + + gaps[ix] = minPrefMax; + } + + private final void mergeGapSizes(int[] sizes, boolean isHor, boolean isTL) + { + if (gaps == null) + gaps = new int[][] {null, null, null, null}; + + if (sizes == null) + return; + + int gapIX = getGapIx(isHor, isTL); + int[] oldGaps = gaps[gapIX]; + if (oldGaps == null) { + oldGaps = new int[] {0, 0, LayoutUtil.INF}; + gaps[gapIX] = oldGaps; + } + + oldGaps[LayoutUtil.MIN] = Math.max(sizes[LayoutUtil.MIN], oldGaps[LayoutUtil.MIN]); + oldGaps[LayoutUtil.PREF] = Math.max(sizes[LayoutUtil.PREF], oldGaps[LayoutUtil.PREF]); + oldGaps[LayoutUtil.MAX] = Math.min(sizes[LayoutUtil.MAX], oldGaps[LayoutUtil.MAX]); + } + + private final int getGapIx(boolean isHor, boolean isTL) + { + return isHor ? (isTL ? 1 : 3) : (isTL ? 0 : 2); + } + + private final String getLinkContext(boolean defBaseline) + { + return isBaselineAlign(defBaseline) ? "baseline" : null; + } + + private final int getSizeInclGaps(int sizeType, boolean isHor) + { + return filter(sizeType, getGapBefore(sizeType, isHor) + getSize(sizeType, isHor) + getGapAfter(sizeType, isHor)); + } + + private final int getSize(int sizeType, boolean isHor) + { + return filter(sizeType, isHor ? horSizes[sizeType] : verSizes[sizeType]); + } + + private final int getGapBefore(int sizeType, boolean isHor) + { + int[] gaps = getGaps(isHor, true); + return gaps != null ? filter(sizeType, gaps[sizeType]) : 0; + } + + private final int getGapAfter(int sizeType, boolean isHor) + { + int[] gaps = getGaps(isHor, false); + return gaps != null ? filter(sizeType, gaps[sizeType]) : 0; + } + + private final int[] getGaps(boolean isHor, boolean isTL) + { + return gaps[getGapIx(isHor, isTL)]; + } + + private final int filter(int sizeType, int size) + { + if (size == LayoutUtil.NOT_SET) + return sizeType != LayoutUtil.MAX ? 0 : LayoutUtil.INF; + return constrainSize(size); + } + + private final boolean isBaselineAlign(boolean defValue) + { + Float g = cc.getVertical().getGrow(); + if (g != null && g.intValue() != 0) + return false; + + UnitValue al = cc.getVertical().getAlign(); + return comp.hasBaseline() && (al != null ? al == UnitValue.BASELINE_IDENTITY : defValue); + } + + private final int getBaseline(int sizeType) + { + return comp.getBaseline(getSize(sizeType, true), getSize(sizeType, false)); + } + } + + //*************************************************************************************** + //* Helper Methods + //*************************************************************************************** + + private static void layoutBaseline(ContainerWrapper parent, ArrayList<CompWrap> compWraps, DimConstraint dc, int start, int size, int sizeType, int spanCount) + { + int[] aboveBelow = getBaselineAboveBelow(compWraps, sizeType, true); + int blRowSize = aboveBelow[0] + aboveBelow[1]; + + CC cc = compWraps.get(0).cc; + + // Align for the whole baseline component array + UnitValue align = cc.getVertical().getAlign(); + if (spanCount == 1 && align == null) + align = dc.getAlignOrDefault(false); + if (align == UnitValue.BASELINE_IDENTITY) + align = UnitValue.CENTER; + + int offset = start + aboveBelow[0] + (align != null ? Math.max(0, align.getPixels(size - blRowSize, parent, null)) : 0); + for (int i = 0, iSz = compWraps.size(); i < iSz; i++) { + CompWrap cw = compWraps.get(i); + cw.y += offset; + + if (cw.y + cw.h > start + size) + cw.h = start + size - cw.y; + } + } + + private static void layoutSerial(ContainerWrapper parent, ArrayList<CompWrap> compWraps, DimConstraint dc, int start, int size, boolean isHor, int spanCount, boolean fromEnd) + { + FlowSizeSpec fss = mergeSizesGapsAndResConstrs( + getComponentResizeConstraints(compWraps, isHor), + getComponentGapPush(compWraps, isHor), + getComponentSizes(compWraps, isHor), + getGaps(compWraps, isHor), + 0, null); + + Float[] growW = dc.isFill() ? GROW_100 : null; + int[] sizes = LayoutUtil.calculateSerial(fss.sizes, fss.resConstsInclGaps, growW, LayoutUtil.PREF, size); + setCompWrapBounds(parent, sizes, compWraps, dc.getAlignOrDefault(isHor), start, size, isHor, fromEnd); + } + + private static void setCompWrapBounds(ContainerWrapper parent, int[] allSizes, ArrayList<CompWrap> compWraps, UnitValue rowAlign, int start, int size, boolean isHor, boolean fromEnd) + { + int totSize = LayoutUtil.sum(allSizes); + CC cc = compWraps.get(0).cc; + UnitValue align = correctAlign(cc, rowAlign, isHor, fromEnd); + + int cSt = start; + int slack = size - totSize; + if (slack > 0 && align != null) { + int al = Math.min(slack, Math.max(0, align.getPixels(slack, parent, null))); + cSt += (fromEnd ? -al : al); + } + + for (int i = 0, bIx = 0, iSz = compWraps.size(); i < iSz; i++) { + CompWrap cw = compWraps.get(i); + if (fromEnd ) { + cSt -= allSizes[bIx++]; + cw.setDimBounds(cSt - allSizes[bIx], allSizes[bIx], isHor); + cSt -= allSizes[bIx++]; + } else { + cSt += allSizes[bIx++]; + cw.setDimBounds(cSt, allSizes[bIx], isHor); + cSt += allSizes[bIx++]; + } + } + } + + private static void layoutParallel(ContainerWrapper parent, ArrayList<CompWrap> compWraps, DimConstraint dc, int start, int size, boolean isHor, int spanCount, boolean fromEnd) + { + int[][] sizes = new int[compWraps.size()][]; // [compIx][gapBef,compSize,gapAft] + + for (int i = 0; i < sizes.length; i++) { + CompWrap cw = compWraps.get(i); + + DimConstraint cDc = cw.cc.getDimConstraint(isHor); + + ResizeConstraint[] resConstr = new ResizeConstraint[] { + cw.isPushGap(isHor, true) ? GAP_RC_CONST_PUSH : GAP_RC_CONST, + cDc.resize, + cw.isPushGap(isHor, false) ? GAP_RC_CONST_PUSH : GAP_RC_CONST, + }; + + int[][] sz = new int[][] { + cw.getGaps(isHor, true), (isHor ? cw.horSizes : cw.verSizes), cw.getGaps(isHor, false) + }; + + Float[] growW = dc.isFill() ? GROW_100 : null; + + sizes[i] = LayoutUtil.calculateSerial(sz, resConstr, growW, LayoutUtil.PREF, size); + } + + UnitValue rowAlign = dc.getAlignOrDefault(isHor); + setCompWrapBounds(parent, sizes, compWraps, rowAlign, start, size, isHor, fromEnd); + } + + private static void setCompWrapBounds(ContainerWrapper parent, int[][] sizes, ArrayList<CompWrap> compWraps, UnitValue rowAlign, int start, int size, boolean isHor, boolean fromEnd) + { + for (int i = 0; i < sizes.length; i++) { + CompWrap cw = compWraps.get(i); + + UnitValue align = correctAlign(cw.cc, rowAlign, isHor, fromEnd); + + int[] cSizes = sizes[i]; + int gapBef = cSizes[0]; + int cSize = cSizes[1]; // No Math.min(size, cSizes[1]) here! + int gapAft = cSizes[2]; + + int cSt = fromEnd ? start - gapBef : start + gapBef; + int slack = size - cSize - gapBef - gapAft; + if (slack > 0 && align != null) { + int al = Math.min(slack, Math.max(0, align.getPixels(slack, parent, null))); + cSt += (fromEnd ? -al : al); + } + + cw.setDimBounds(fromEnd ? cSt - cSize : cSt, cSize, isHor); + } + } + + private static UnitValue correctAlign(CC cc, UnitValue rowAlign, boolean isHor, boolean fromEnd) + { + UnitValue align = (isHor ? cc.getHorizontal() : cc.getVertical()).getAlign(); + if (align == null) + align = rowAlign; + if (align == UnitValue.BASELINE_IDENTITY) + align = UnitValue.CENTER; + + if (fromEnd) { + if (align == UnitValue.LEFT) + align = UnitValue.RIGHT; + else if (align == UnitValue.RIGHT) + align = UnitValue.LEFT; + } + return align; + } + + private static int[] getBaselineAboveBelow(ArrayList<CompWrap> compWraps, int sType, boolean centerBaseline) + { + int maxAbove = Short.MIN_VALUE; + int maxBelow = Short.MIN_VALUE; + for (int i = 0, iSz = compWraps.size(); i < iSz; i++) { + CompWrap cw = compWraps.get(i); + + int height = cw.getSize(sType, false); + if (height >= LayoutUtil.INF) + return new int[] {LayoutUtil.INF / 2, LayoutUtil.INF / 2}; + + int baseline = cw.getBaseline(sType); + int above = baseline + cw.getGapBefore(sType, false); + maxAbove = Math.max(above, maxAbove); + maxBelow = Math.max(height - baseline + cw.getGapAfter(sType, false), maxBelow); + + if (centerBaseline) + cw.setDimBounds(-baseline, height, false); + } + return new int[] {maxAbove, maxBelow}; + } + + private static int getTotalSizeParallel(ArrayList<CompWrap> compWraps, int sType, boolean isHor) + { + int size = sType == LayoutUtil.MAX ? LayoutUtil.INF : 0; + + for (int i = 0, iSz = compWraps.size(); i < iSz; i++) { + CompWrap cw = compWraps.get(i); + int cwSize = cw.getSizeInclGaps(sType, isHor); + if (cwSize >= LayoutUtil.INF) + return LayoutUtil.INF; + + if (sType == LayoutUtil.MAX ? cwSize < size : cwSize > size) + size = cwSize; + } + return constrainSize(size); + } + + private static final int getTotalSizeSerial(ArrayList<CompWrap> compWraps, int sType, boolean isHor) + { + int totSize = 0; + for (int i = 0, iSz = compWraps.size(), lastGapAfter = 0; i < iSz; i++) { + CompWrap wrap = compWraps.get(i); + int gapBef = wrap.getGapBefore(sType, isHor); + if (gapBef > lastGapAfter) + totSize += gapBef - lastGapAfter; + + totSize += wrap.getSize(sType, isHor); + totSize += (lastGapAfter = wrap.getGapAfter(sType, isHor)); + + if (totSize >= LayoutUtil.INF) + return LayoutUtil.INF; + } + return constrainSize(totSize); + } + + private static final int getTotalGroupsSizeParallel(ArrayList<LinkedDimGroup> groups, int sType, boolean countSpanning) + { + int size = sType == LayoutUtil.MAX ? LayoutUtil.INF : 0; + for (int i = 0, iSz = groups.size(); i < iSz; i++) { + LinkedDimGroup group = groups.get(i); + if (countSpanning || group.span == 1) { + int grpSize = group.getMinPrefMax()[sType]; + if (grpSize >= LayoutUtil.INF) + return LayoutUtil.INF; + + if (sType == LayoutUtil.MAX ? grpSize < size : grpSize > size) + size = grpSize; + } + } + return constrainSize(size); + } + + /** + * @param compWraps + * @param isHor + * @return Might contain LayoutUtil.NOT_SET + */ + private static int[][] getComponentSizes(ArrayList<CompWrap> compWraps, boolean isHor) + { + int[][] compSizes = new int[compWraps.size()][]; + for (int i = 0; i < compSizes.length; i++) { + CompWrap cw = compWraps.get(i); + compSizes[i] = isHor ? cw.horSizes : cw.verSizes; + } + return compSizes; + } + + /** Merges sizes and gaps together with Resize Constraints. For gaps {@link #GAP_RC_CONST} is used. + * @param resConstr One resize constriant for every row/component. Can be lesser in length and the last element should be used for missing elements. + * @param gapPush If the corresponding gap should be considered pushing and thus want to take free space if left over. Should be one more than resConstrs! + * @param minPrefMaxSizes The sizes (min/pref/max) for every row/component. + * @param gapSizes The gaps before and after each row/component packed in one double sized array. + * @param refSize The reference size to get the gap in pixels. + * @param parent The parent used to get the gap in pixels. + * @return A holder for the merged values. + */ + private static FlowSizeSpec mergeSizesGapsAndResConstrs(ResizeConstraint[] resConstr, boolean[] gapPush, int[][] minPrefMaxSizes, int[][] gapSizes, int refSize, ContainerWrapper parent) + { + int[][] sizes = new int[(minPrefMaxSizes.length << 1) + 1][]; // Make room for gaps around. + ResizeConstraint[] resConstsInclGaps = new ResizeConstraint[sizes.length]; + + sizes[0] = gapSizes[0]; + for (int i = 0, crIx = 1; i < minPrefMaxSizes.length; i++, crIx += 2) { + + // Component bounds and constraints + resConstsInclGaps[crIx] = resConstr[i]; + sizes[crIx] = minPrefMaxSizes[i]; + + sizes[crIx + 1] = gapSizes[i + 1]; + + if (sizes[crIx - 1] != null) + resConstsInclGaps[crIx - 1] = gapPush[i < gapPush.length ? i : gapPush.length - 1] ? GAP_RC_CONST_PUSH : GAP_RC_CONST; + + if (i == (minPrefMaxSizes.length - 1) && sizes[crIx + 1] != null) + resConstsInclGaps[crIx + 1] = gapPush[(i + 1) < gapPush.length ? (i + 1) : gapPush.length - 1] ? GAP_RC_CONST_PUSH : GAP_RC_CONST; + } + + // Check for null and set it to 0, 0, 0. + for (int i = 0; i < sizes.length; i++) { + if (sizes[i] == null) + sizes[i] = new int[3]; + } + + return new FlowSizeSpec(sizes, resConstsInclGaps); + } + + private static final int[] mergeSizes(int[] oldValues, int[] newValues) + { + if (oldValues == null) + return newValues; + + if (newValues == null) + return oldValues; + + int[] ret = new int[oldValues.length]; + for (int i = 0; i < ret.length; i++) + ret[i] = mergeSizes(oldValues[i], newValues[i], true); + + return ret; + } + + private static final int mergeSizes(int oldValue, int newValue, boolean toMax) + { + if (oldValue == LayoutUtil.NOT_SET || oldValue == newValue) + return newValue; + + if (newValue == LayoutUtil.NOT_SET) + return oldValue; + + return toMax != oldValue > newValue ? newValue : oldValue; + } + + private static final int constrainSize(int s) + { + return s > 0 ? (s < LayoutUtil.INF ? s : LayoutUtil.INF) : 0; + } + + private static final void correctMinMax(int s[]) + { + if (s[LayoutUtil.MIN] > s[LayoutUtil.MAX]) + s[LayoutUtil.MIN] = s[LayoutUtil.MAX]; // Since MAX is almost always explicitly set use tha + + if (s[LayoutUtil.PREF] < s[LayoutUtil.MIN]) + s[LayoutUtil.PREF] = s[LayoutUtil.MIN]; + + if (s[LayoutUtil.PREF] > s[LayoutUtil.MAX]) + s[LayoutUtil.PREF] = s[LayoutUtil.MAX]; + } + + private static final class FlowSizeSpec + { + private final int[][] sizes; + private final ResizeConstraint[] resConstsInclGaps; + + private FlowSizeSpec(int[][] sizes, ResizeConstraint[] resConstsInclGaps) + { + this.sizes = sizes; + this.resConstsInclGaps = resConstsInclGaps; + } + + /** + * @param specs The specs for the columns or rows. Last index will be used of <code>fromIx + len</code> is greater than this array's length. + * @param targetSize The size to try to meat. + * @param defGrow The default grow weight if the specs does not have anyone that will grow. Comes from "push" in the CC. + * @param fromIx + * @param len + * @param sizeType + * @param eagerness How eager the algorithm should be to try to expand the sizes. + * <ul> + * <li>0 - Grow only rows/columns which has the <code>sizeType</code> set to be the containing components AND which has a grow weight > 0. + * <li>1 - Grow only rows/columns which has the <code>sizeType</code> set to be the containing components AND which has a grow weight > 0 OR unspecified. + * <li>2 - Grow all rows/columns that has a grow weight > 0. + * <li>3 - Grow all rows/columns that has a grow weight > 0 OR unspecified. + * </ul> + * @return The new size. + */ + private final int expandSizes(DimConstraint[] specs, Float[] defGrow, int targetSize, int fromIx, int len, int sizeType, int eagerness) + { + ResizeConstraint[] resConstr = new ResizeConstraint[len]; + int[][] sizesToExpand = new int[len][]; + for (int i = 0; i < len; i++) { + int size = sizes[i + fromIx][sizeType]; + sizesToExpand[i] = new int[] {size, size, sizes[i + fromIx][LayoutUtil.MAX]}; + + if (eagerness <= 1 && i % 2 == 0) { // // (i % 2 == 0) means only odd indexes, which is only rows/col indexes and not gaps. + int cIx = (i + fromIx - 1) >> 1; + DimConstraint spec = (DimConstraint) LayoutUtil.getIndexSafe(specs, cIx); + + if ( (sizeType == LayoutUtil.MIN && spec.getSize() != null && spec.getSize().getMin() != null && spec.getSize().getMin().getUnit() != UnitValue.MIN_SIZE) || + (sizeType == LayoutUtil.PREF && spec.getSize() != null && spec.getSize().getPreferred() != null && spec.getSize().getPreferred().getUnit() != UnitValue.PREF_SIZE)) { + continue; + } + } + resConstr[i] = (ResizeConstraint) LayoutUtil.getIndexSafe(resConstsInclGaps, i + fromIx); + } + + Float[] growW = (eagerness == 1 || eagerness == 3) ? extractSubArray(specs, defGrow, fromIx, len): null; + int[] newSizes = LayoutUtil.calculateSerial(sizesToExpand, resConstr, growW, sizeType, targetSize); + int newSize = 0; + + for (int i = 0; i < len; i++) { + int s = newSizes[i]; + sizes[i + fromIx][sizeType] = s; + newSize += s; + } + return newSize; + } + } + + private static Float[] extractSubArray(DimConstraint[] specs, Float[] arr, int ix, int len) + { + if (arr == null || arr.length < ix + len) { + Float[] growLastArr = new Float[len]; + + // Handle a group where some rows (first one/few and/or last one/few) are docks. + for (int i = ix + len - 1; i >= 0; i -= 2) { + int specIx = (i >> 1); + if (specs[specIx] != DOCK_DIM_CONSTRAINT) { + growLastArr[i - ix] = ResizeConstraint.WEIGHT_100; + return growLastArr; + } + } + return growLastArr; + } + + Float[] newArr = new Float[len]; + for (int i = 0; i < len; i++) + newArr[i] = arr[ix + i]; + return newArr; + } + + private static WeakHashMap[] PARENT_ROWCOL_SIZES_MAP = null; + static synchronized void putSizesAndIndexes(Object parComp, int[] sizes, int[] ixArr, boolean isRows) + { + if (PARENT_ROWCOL_SIZES_MAP == null) // Lazy since only if designing in IDEs + PARENT_ROWCOL_SIZES_MAP = new WeakHashMap[] {new WeakHashMap(4), new WeakHashMap(4)}; + + PARENT_ROWCOL_SIZES_MAP[isRows ? 0 : 1].put(parComp, new int[][] {ixArr, sizes}); + } + + static synchronized int[][] getSizesAndIndexes(Object parComp, boolean isRows) + { + if (PARENT_ROWCOL_SIZES_MAP == null) + return null; + + return (int[][]) PARENT_ROWCOL_SIZES_MAP[isRows ? 0 : 1].get(parComp); + } +} diff --git a/prototypes/miglayout/net/miginfocom/layout/IDEUtil.java b/prototypes/miglayout/net/miginfocom/layout/IDEUtil.java index b52d37df..600bb810 100644 --- a/prototypes/miglayout/net/miginfocom/layout/IDEUtil.java +++ b/prototypes/miglayout/net/miginfocom/layout/IDEUtil.java @@ -1,704 +1,704 @@ -package net.miginfocom.layout;
-/*
- * License (BSD):
- * ==============
- *
- * Copyright (c) 2004, Mikael Grev, MiG InfoCom AB. (miglayout (at) miginfocom (dot) com)
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification,
- * are permitted provided that the following conditions are met:
- * Redistributions of source code must retain the above copyright notice, this list
- * of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above copyright notice, this
- * list of conditions and the following disclaimer in the documentation and/or other
- * materials provided with the distribution.
- * Neither the name of the MiG InfoCom AB nor the names of its contributors may be
- * used to endorse or promote products derived from this software without specific
- * prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
- * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
- * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
- * OF SUCH DAMAGE.
- *
- * @version 1.0
- * @author Mikael Grev, MiG InfoCom AB
- * Date: 2006-sep-08
- */
-
-/** This class contains static methods to be used by IDE vendors to convert to and from String/API constraints.
- * <p>
- * <b>Note that {@link LayoutUtil#setDesignTime(boolean)} should be set to <code>true</code> for this class'
- * methods to work.</b>
- */
-public class IDEUtil
-{
- /** A direct reference to the corresponding value for predefined UnitValues in {@link UnitValue}.
- */
- public static final UnitValue ZERO = UnitValue.ZERO;
-
- /** A direct reference to the corresponding value for predefined UnitValues in {@link UnitValue}.
- */
- public static final UnitValue TOP = UnitValue.TOP;
-
- /** A direct reference to the corresponding value for predefined UnitValues in {@link UnitValue}.
- */
- public static final UnitValue LEADING = UnitValue.LEADING;
-
- /** A direct reference to the corresponding value for predefined UnitValues in {@link UnitValue}.
- */
- public static final UnitValue LEFT = UnitValue.LEFT;
-
- /** A direct reference to the corresponding value for predefined UnitValues in {@link UnitValue}.
- */
- public static final UnitValue CENTER = UnitValue.CENTER;
-
- /** A direct reference to the corresponding value for predefined UnitValues in {@link UnitValue}.
- */
- public static final UnitValue TRAILING = UnitValue.TRAILING;
-
- /** A direct reference to the corresponding value for predefined UnitValues in {@link UnitValue}.
- */
- public static final UnitValue RIGHT = UnitValue.RIGHT;
-
- /** A direct reference to the corresponding value for predefined UnitValues in {@link UnitValue}.
- */
- public static final UnitValue BOTTOM = UnitValue.BOTTOM;
-
- /** A direct reference to the corresponding value for predefined UnitValues in {@link UnitValue}.
- */
- public static final UnitValue LABEL = UnitValue.LABEL;
-
- /** A direct reference to the corresponding value for predefined UnitValues in {@link UnitValue}.
- */
- public static final UnitValue INF = UnitValue.INF;
-
- /** A direct reference to the corresponding value for predefined UnitValues in {@link UnitValue}.
- */
- public static final UnitValue BASELINE_IDENTITY = UnitValue.BASELINE_IDENTITY;
-
- private final static String[] X_Y_STRINGS = new String[] {"x", "y", "x2", "y2"};
-
- /** Returns the sizes of the rows and gaps for a container. * There will be two arrays returned [0] and [1].
- * <p>
- * The first array will be the indexes of the rows where indexes that
- * are less than 30000 or larger than 30000 is docking rows. There might be extra docking rows that aren't
- * visible but they always have size 0. Non docking indexes will probably always be 0, 1, 2, 3, etc..
- * <p>
- * The second array is the sizes of the form:<br>
- * <code>[left inset][row size 1][gap 1][row size 2][gap 2][row size n][right inset]</code>.
- * <p>
- * The returned sizes will be the ones calculated in the last layout cycle.
- * @param parentContainer The container to retuern the row sizes and gaps for. In Swing it will be a {@link java.awt.Container} and
- * in SWT it will be a {@link org.eclipse.swt.widgets.Composite}.
- * @return The sizes or <code>null</code> if {@link LayoutUtil#isDesignTime()} is <code>false</code> or
- * <code>parentContainer</code> does not have a MigLayout layout manager.
- * The returned sizes will be the ones calculated in the last layout cycle.
- * @see LayoutUtil#isDesignTime()
- */
- public static int[][] getRowSizes(Object parentContainer)
- {
- return Grid.getSizesAndIndexes(parentContainer, true);
- }
-
- /** Returns the sizes of the columns and gaps for a container.
- * There will be two arrays returned [0] and [1].
- * <p>
- * The first array will be the indexes of the columns where indexes that
- * are less than 30000 or larger than 30000 is docking columns. There might be extra docking columns that aren't
- * visible but they always have size 0. Non docking indexes will probably always be 0, 1, 2, 3, etc..
- * <p>
- * The second array is the sizes of the form:<br>
- * <code>[top inset][column size 1][gap 1][column size 2][gap 2][column size n][bottom inset]</code>.
- * <p>
- * The returned sizes will be the ones calculated in the last layout cycle.
- * @param parentContainer The container to retuern the column sizes and gaps for. In Swing it will be a {@link java.awt.Container} and
- * in SWT it will be a {@link org.eclipse.swt.widgets.Composite}.
- * @return The sizes and indexes or <code>null</code> if {@link LayoutUtil#isDesignTime()} is <code>false</code> or
- * <code>parentContainer</code> does not have a MigLayout layout manager.
- * The returned sizes will be the ones calculated in the last layout cycle.
- * @see LayoutUtil#isDesignTime()
- */
- public static int[][] getColumnSizes(Object parentContainer)
- {
- return Grid.getSizesAndIndexes(parentContainer, false);
- }
-
- /** Returns the a constraint string that can be re-parsed to be the exact same AxisConstraint.
- * @param ac The axis constraint to return as a constraint string.
- * @param asAPI If the returned string should be of API type (e.g. .flowX().gap("rel").align("right")) or
- * as a String type (e.g. "flowx, gap rel, right").
- * @param isCols The the constraint should be returned for columns rather than rows.
- * @return A String. Never <code>null</code>.
- */
- public static final String getConstraintString(AC ac, boolean asAPI, boolean isCols)
- {
- StringBuffer sb = new StringBuffer(32);
-
- DimConstraint[] dims = ac.getConstaints();
- BoundSize defGap = isCols ? PlatformDefaults.getGridGapX() : PlatformDefaults.getGridGapY();
-
- for (int i = 0; i < dims.length; i++) {
- DimConstraint dc = dims[i];
-
- addRowDimConstraintString(dc, sb, asAPI);
-
- if (i < dims.length - 1) {
- BoundSize gapAft = dc.getGapAfter();
- BoundSize gapBefNext = dims[i + 1].getGapBefore();
-
- if (gapAft != null && gapAft == gapBefNext && gapAft != defGap) {
- if (asAPI) {
- sb.append(".gap(\"").append(getBS(gapAft)).append("\")");
- } else {
- sb.append(getBS(gapAft));
- }
- } else {
- if (asAPI)
- sb.append(".gap()");
- }
- }
- }
-
- return sb.toString();
- }
-
- /** Adds the a constraint string that can be re-parsed to be the exact same DimConstraint.
- * @param dc The layout constraint to return as a constraint string.
- * @param asAPI If the returned string should be of API type (e.g. .flowX().gap("rel").align("right")) or
- * as a String type (e.g. "flowx, gap rel, right").
- */
- private static final void addRowDimConstraintString(DimConstraint dc, StringBuffer sb, boolean asAPI)
- {
- int gp = dc.getGrowPriority();
-
- int firstComma = sb.length();
-
- BoundSize size = dc.getSize();
- if (size != null) {
- if (asAPI) {
- sb.append(".size(\"").append(getBS(size)).append("\")");
- } else {
- sb.append(',').append(getBS(size));
- }
- }
-
- if (gp != 100) {
- if (asAPI) {
- sb.append(".growPrio(").append(gp).append("\")");
- } else {
- sb.append(",growprio ").append(gp);
- }
- }
-
- Float gw = dc.getGrow();
- if (gw != null) {
- String g = gw.floatValue() != 100f ? LayoutUtil.floatToString(gw.floatValue()) : "";
- if (asAPI) {
- if (g.length() == 0) {
- sb.append(".grow()");
- } else {
- sb.append(".grow(\"").append(g).append("\")");
- }
- } else {
- sb.append(",grow").append(g.length() > 0 ? (" " + g) : "");
- }
- }
-
- int sp = dc.getShrinkPriority();
- if (sp != 100) {
- if (asAPI) {
- sb.append(".shrinkPrio(").append(sp).append("\")");
- } else {
- sb.append(",shrinkprio ").append(sp);
- }
- }
-
- Float sw = dc.getShrink();
- if (sw != null && sw.intValue() != 100) {
- String s = LayoutUtil.floatToString(sw.floatValue());
- if (asAPI) {
- sb.append(".shrink(\"").append(s).append("\")");
- } else {
- sb.append(",shrink ").append(s);
- }
- }
-
- String eg = dc.getEndGroup();
- if (eg != null) {
- if (asAPI) {
- sb.append(".endGroup(\"").append(eg).append("\")");
- } else {
- sb.append(",endgroup ").append(eg);
- }
- }
-
- String sg = dc.getSizeGroup();
- if (sg != null) {
- if (asAPI) {
- sb.append(".sizeGroup(\"").append(sg).append("\")");
- } else {
- sb.append(",sizegroup ").append(sg);
- }
- }
-
- UnitValue al = dc.getAlign();
- if (al != null) {
- if (asAPI) {
- sb.append(".align(\"").append(getUV(al)).append("\")");
- } else {
- String s = getUV(al);
- String alKw = (s.equals("top") || s.equals("bottom") || s.equals("left") || s.equals("label") ||
- s.equals("leading") || s.equals("center") || s.equals("trailing") ||
- s.equals("right") || s.equals("baseline")) ? "" : "align ";
- sb.append(',').append(alKw).append(s);
- }
- }
-
- if (dc.isNoGrid()) {
- if (asAPI) {
- sb.append(".noGrid()");
- } else {
- sb.append(",nogrid");
- }
- }
-
- if (dc.isFill()) {
- if (asAPI) {
- sb.append(".fill()");
- } else {
- sb.append(",fill");
- }
- }
-
- if (asAPI == false) {
- if (sb.length() > firstComma) {
- sb.setCharAt(firstComma, '[');
- sb.append(']');
- } else {
- sb.append("[]");
- }
- }
- }
-
- /** Returns the a constraint string that can be re-parsed to be the exact same DimConstraint.
- * @param dc The layout constraint to return as a constraint string.
- * @param asAPI If the returned string should be of API type (e.g. .flowX().gap("rel").align("right")) or
- * as a String type (e.g. "flowx, gap rel, right").
- * @param isHor The the DimConstraint is decoration something horizontal (column or x).
- * @param noGrowAdd If <code>true</code> no grow constraints will be added.
- * @return A constraint string. Never <code>null</code>.
- */
- private static final void addComponentDimConstraintString(DimConstraint dc, StringBuffer sb, boolean asAPI, boolean isHor, boolean noGrowAdd)
- {
- int gp = dc.getGrowPriority();
- if (gp != 100) {
- if (asAPI) {
- sb.append(isHor ? ".growPrioX(" : ".growPrioY(").append(gp).append(')');
- } else {
- sb.append(isHor ? ",growpriox " : ",growprioy ").append(gp);
- }
- }
-
- if (noGrowAdd == false) {
- Float gw = dc.getGrow();
- if (gw != null) {
- String g = gw.floatValue() != 100f ? LayoutUtil.floatToString(gw.floatValue()) : "";
- if (asAPI) {
- sb.append(isHor ? ".growX(" : ".growY(").append(g).append(')');
- } else {
- sb.append(isHor ? ",growx" : ",growy").append(g.length() > 0 ? (" " + g) : "");
- }
- }
- }
-
- int sp = dc.getShrinkPriority();
- if (sp != 100) {
- if (asAPI) {
- sb.append(isHor ? ".shrinkPrioX(" : ".shrinkPrioY(").append(sp).append(')');
- } else {
- sb.append(isHor ? ",shrinkpriox " : ",shrinkprioy ").append(sp);
- }
- }
-
- Float sw = dc.getShrink();
- if (sw != null && sw.intValue() != 100) {
- String s = LayoutUtil.floatToString(sw.floatValue());
- if (asAPI) {
- sb.append(isHor ? ".shrinkX(" : ".shrinkY(").append(s).append(')');
- } else {
- sb.append(isHor ? ",shrinkx " : ",shrinky ").append(s);
- }
- }
-
- String eg = dc.getEndGroup();
- if (eg != null) {
- if (asAPI) {
- sb.append(isHor ? ".endGroupX(\"" : ".endGroupY(\"").append(eg).append("\")");
- } else {
- sb.append(isHor ? ",endgroupx " : ",endgroupy ").append(eg);
- }
- }
-
- String sg = dc.getSizeGroup();
- if (sg != null) {
- if (asAPI) {
- sb.append(isHor ? ".sizeGroupX(\"" : ".sizeGroupY(\"").append(sg).append("\")");
- } else {
- sb.append(isHor ? ",sizegroupx " : ",sizegroupy ").append(sg);
- }
- }
-
- BoundSize size = dc.getSize();
- if (size != null) {
- if (size.getPreferred() == null) {
- if (size.getMin() == null) {
- if (asAPI) {
- sb.append(isHor ? ".maxWidth(\"" : ".maxHeight(\"").append(getBS(size)).append("\")");
- } else {
- sb.append(isHor ? ",wmax " : ",hmax ").append(getBS(size));
- }
-
- } else if (size.getMax() == null) {
- if (asAPI) {
- sb.append(isHor ? ".minWidth(\"" : ".minHeight(\"").append(getBS(size)).append("\")");
- } else {
- sb.append(isHor ? ",wmin " : ",hmin ").append(getBS(size));
- }
- }
- } else {
- if (asAPI) {
- sb.append(isHor ? ".width(\"" : ".height(\"").append(getBS(size)).append("\")");
- } else {
- sb.append(isHor ? ",width " : ",height ").append(getBS(size));
- }
- }
- }
-
- UnitValue al = dc.getAlign();
- if (al != null) {
- if (asAPI) {
- sb.append(isHor ? ".alignX(\"" : ".alignY(\"").append(getUV(al)).append("\")");
- } else {
- sb.append(isHor ? ",alignx " : ",aligny ").append(getUV(al));
- }
- }
-
- BoundSize gapBef = dc.getGapBefore();
- BoundSize gapAft= dc.getGapAfter();
- if (gapBef != null || gapAft != null) {
- if (asAPI) {
- sb.append(isHor ? ".gapX(\"" : ".gapY(\"").append(getBS(gapBef)).append("\", \"").append(getBS(gapAft)).append("\")");
- } else {
- sb.append(isHor ? ",gapx " : ",gapy ").append(getBS(gapBef)).append(' ').append(getBS(gapAft));
- }
- }
- }
-
- /** Returns the a constraint string that can be re-parsed to be the exact same LayoutConstraint.
- * @param cc The component constraint to return as a constraint string.
- * @param asAPI If the returned string should be of API type (e.g. .flowX().gap("rel").align("right")) or
- * as a String type (e.g. "flowx, gap rel, right").
- * @return A String. Never <code>null</code>.
- */
- public static final String getConstraintString(CC cc, boolean asAPI)
- {
- StringBuffer sb = new StringBuffer(16);
-
- if (cc.isNewline())
- sb.append(asAPI ? ".newline()" : ",newline");
-
- if (cc.isExternal())
- sb.append(asAPI ? ".external()" : ",external");
-
- Boolean flowX = cc.getFlowX();
- if (flowX != null) {
- if (asAPI) {
- sb.append(flowX.booleanValue() ? ".flowX()" : ".flowY()");
- } else {
- sb.append(flowX.booleanValue() ? ",flowx" : ",flowy");
- }
- }
-
- UnitValue[] pad = cc.getPadding();
- if (pad != null) {
- sb.append(asAPI ? ".pad(\"" : ",pad ");
- for (int i = 0; i < pad.length; i++)
- sb.append(getUV(pad[i])).append(i < pad.length - 1 ? " " : "");
- if (asAPI)
- sb.append("\")");
- }
-
- UnitValue[] pos = cc.getPos();
- if (pos != null) {
- if (cc.isBoundsInGrid()) {
- for (int i = 0; i < 4; i++) {
- if (pos[i] != null) {
- if (asAPI) {
- sb.append('.').append(X_Y_STRINGS[i]).append("(\"").append(getUV(pos[i])).append("\")");
- } else {
- sb.append(',').append(X_Y_STRINGS[i]).append(getUV(pos[i]));
- }
- }
- }
- } else {
- sb.append(asAPI ? ".pos(\"" : ",pos ");
- int iSz = (pos[2] != null || pos[3] != null) ? 4 : 2; // "pos x y" vs "pos x1 y1 x2 y2".
- for (int i = 0; i < iSz; i++)
- sb.append(getUV(pos[i])).append(i < iSz - 1 ? " " : "");
-
- if (asAPI)
- sb.append("\")");
- }
- }
-
- String id = cc.getId();
- if (id != null) {
- if (asAPI) {
- sb.append(".id(\"").append(id).append("\")");
- } else {
- sb.append(",id ").append(id);
- }
- }
-
- String tag = cc.getTag();
- if (tag != null) {
- if (asAPI) {
- sb.append(".tag(\"").append(tag).append("\")");
- } else {
- sb.append(",tag ").append(tag);
- }
- }
-
- int hideMode = cc.getHideMode();
- if (hideMode >= 0) {
- if (asAPI) {
- sb.append(".hideMode(").append(hideMode).append(')');
- } else {
- sb.append(",hideMode ").append(hideMode);
- }
- }
-
- int skip = cc.getSkip();
- if (skip > 0) {
- if (asAPI) {
- sb.append(".skip(").append(skip).append(')');
- } else {
- sb.append(",skip ").append(skip);
- }
- }
-
- int split = cc.getSplit();
- if (split > 1) {
- String s = split == LayoutUtil.INF ? "" : String.valueOf(split);
- if (asAPI) {
- sb.append(".split(").append(s).append(')');
- } else {
- sb.append(",split ").append(s);
- }
- }
-
- int cx = cc.getCellX();
- int cy = cc.getCellY();
- int spanX = cc.getSpanX();
- int spanY = cc.getSpanY();
- if (cx >= 0 && cy >= 0) {
- if (asAPI) {
- sb.append(".cell(").append(cx).append(", ").append(cy);
- if (spanX > 1 || spanY > 1)
- sb.append(", ").append(spanX).append(", ").append(spanY);
- sb.append(')');
- } else {
- sb.append(",cell ").append(cx).append(' ').append(cy);
- if (spanX > 1 || spanY > 1)
- sb.append(' ').append(spanX).append(' ').append(spanY);
- }
- } else if (spanX > 1 || spanY > 1) {
- if (spanX > 1 && spanY > 1) {
- sb.append(asAPI ? ".span(" : ",span ").append(spanX).append(asAPI ? ", " : " ").append(spanY);
- } else if (spanX > 1) {
- sb.append(asAPI ? ".spanX(" : ",spanx ").append(spanX == LayoutUtil.INF ? "" : (String.valueOf(spanX)));
- } else if (spanY > 1) {
- sb.append(asAPI ? ".spanY(" : ",spany ").append(spanY == LayoutUtil.INF ? "" : (String.valueOf(spanY)));
- }
- if (asAPI)
- sb.append(')');
- }
-
- Float pushX = cc.getPushX();
- Float pushY = cc.getPushY();
- if (pushX != null || pushY != null) {
- if (pushX != null && pushY != null) {
- sb.append(asAPI ? ".push(" : ",push ");
- if (pushX != 100.0 || pushY != 100.0)
- sb.append(pushX).append(asAPI ? ", " : " ").append(pushY);
- } else if (pushX != null) {
- sb.append(asAPI ? ".pushX(" : ",pushx ").append(pushX == 100 ? "" : (String.valueOf(pushX)));
- } else if (pushY != null) {
- sb.append(asAPI ? ".pushY(" : ",pushy ").append(pushY == 100 ? "" : (String.valueOf(pushY)));
- }
- if (asAPI)
- sb.append(')');
- }
-
- int dock = cc.getDockSide();
- if (dock >= 0) {
- String ds = CC.DOCK_SIDES[dock];
- if (asAPI) {
- sb.append(".dock").append(Character.toUpperCase(ds.charAt(0))).append(ds.substring(1)).append("()");
- } else {
- sb.append(",").append(ds);
- }
- }
-
- boolean noGrowAdd = cc.getHorizontal().getGrow() != null && cc.getHorizontal().getGrow().intValue() == 100 &&
- cc.getVertical().getGrow() != null && cc.getVertical().getGrow().intValue() == 100;
-
- addComponentDimConstraintString(cc.getHorizontal(), sb, asAPI, true, noGrowAdd);
- addComponentDimConstraintString(cc.getVertical(), sb, asAPI, false, noGrowAdd);
- if (noGrowAdd)
- sb.append(asAPI ? ".grow()" : ",grow"); // Combine ".growX().growY()" into ".grow()".
-
- if (cc.isWrap())
- sb.append(asAPI ? ".wrap()" : ",wrap");
-
- String s = sb.toString();
- return s.length() == 0 || s.charAt(0) != ',' ? s : s.substring(1);
- }
-
- /** Returns the a constraint string that can be re-parsed to be the exact same LayoutConstraint.
- * @param lc The layout constraint to return as a constraint string.
- * @param asAPI If the returned string should be of API type (e.g. .flowX().gap("rel").align("right")) or
- * as a String type (e.g. "flowx, gap rel, right").
- * @return A String. Never <code>null</code>.
- */
- public static final String getConstraintString(LC lc, boolean asAPI)
- {
- StringBuffer sb = new StringBuffer(16);
-
- if (lc.isFlowX() == false)
- sb.append(asAPI ? ".flowY()" : ",flowy");
-
- boolean fillX = lc.isFillX();
- boolean fillY = lc.isFillY();
- if (fillX || fillY) {
- if (fillX == fillY) {
- sb.append(asAPI ? ".fill()" : ",fill");
- } else {
- sb.append(asAPI ? (fillX ? ".fillX()" : ".fillY()") : (fillX ? ",fillx" : ",filly"));
- }
- }
-
- Boolean leftToRight = lc.getLeftToRight();
- if (leftToRight != null) {
- if (asAPI) {
- sb.append(".leftToRight(").append(leftToRight).append(')');
- } else {
- sb.append(leftToRight.booleanValue() ? ",ltr" : ",rtl");
- }
- }
-
- if (lc.isTopToBottom() == false)
- sb.append(asAPI ? ".bottomToTop()" : ",btt");
-
- UnitValue[] insets = lc.getInsets();
- if (insets != null) {
- String cs = LayoutUtil.getCCString(insets);
- if (cs != null) {
- if (asAPI) {
- sb.append(".insets(\"").append(cs).append("\")");
- } else {
- sb.append(",insets ").append(cs);
- }
- } else {
- sb.append(asAPI ? ".insets(\"" : ",insets ");
- for (int i = 0; i < insets.length; i++)
- sb.append(getUV(insets[i])).append(i < insets.length - 1 ? " " : "");
- if (asAPI)
- sb.append("\")");
- }
- }
-
- if (lc.isNoGrid())
- sb.append(asAPI ? ".noGrid()" : ",nogrid");
-
- if (lc.isVisualPadding() == false)
- sb.append(asAPI ? ".noVisualPadding()" : ",novisualpadding");
-
- int hideMode = lc.getHideMode();
- if (hideMode > 0) {
- if (asAPI) {
- sb.append(".hideMode(").append(hideMode).append(')');
- } else {
- sb.append(",hideMode ").append(hideMode);
- }
- }
-
- UnitValue alignX = lc.getAlignX();
- UnitValue alignY = lc.getAlignY();
- if (alignX != null || alignY != null) {
- if (alignX != null && alignY != null) {
- sb.append(asAPI ? ".align(\"" : ",align ").append(getUV(alignX)).append(' ').append(getUV(alignY));
- } else if (alignX != null) {
- sb.append(asAPI ? ".alignX(\"" : ",alignx ").append(getUV(alignX));
- } else if (alignY != null) {
- sb.append(asAPI ? ".alignY(\"" : ",aligny ").append(getUV(alignY));
- }
- if (asAPI)
- sb.append("\")");
- }
-
- BoundSize gridGapX = lc.getGridGapX();
- BoundSize gridGapY = lc.getGridGapY();
- if (gridGapX != null || gridGapY != null) {
- if (gridGapX != null && gridGapY != null) {
- sb.append(asAPI ? ".gridGap(\"" : ",gap ").append(getBS(gridGapX)).append(' ').append(getBS(gridGapY));
- } else if (gridGapX != null) {
- sb.append(asAPI ? ".gridGapX(\"" : ",gapx ").append(getBS(gridGapX));
- } else if (gridGapY != null) {
- sb.append(asAPI ? ".gridGapY(\"" : ",gapy ").append(getBS(gridGapY));
- }
- if (asAPI)
- sb.append("\")");
- }
-
- int wrapAfter = lc.getWrapAfter();
- if (wrapAfter != LayoutUtil.INF) {
- String ws = wrapAfter > 0 ? String.valueOf(wrapAfter) : "";
- if (asAPI) {
- sb.append(".wrap(").append(ws).append(')');
- } else {
- sb.append(",wrap ").append(ws);
- }
- }
-
- int debugMillis = lc.getDebugMillis();
- if (debugMillis > 0) {
- if (asAPI) {
- sb.append(".debug(").append(debugMillis).append(')');
- } else {
- sb.append(",debug ").append(debugMillis);
- }
- }
-
- String s = sb.toString();
- return s.length() == 0 || s.charAt(0) != ',' ? s : s.substring(1);
- }
-
- private static String getUV(UnitValue uv)
- {
- return uv != null ? uv.getConstraintString() : "null";
- }
-
- private static String getBS(BoundSize bs)
- {
- return bs != null ? bs.getConstraintString() : "null";
- }
-}
+package net.miginfocom.layout; +/* + * License (BSD): + * ============== + * + * Copyright (c) 2004, Mikael Grev, MiG InfoCom AB. (miglayout (at) miginfocom (dot) com) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright notice, this list + * of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * Neither the name of the MiG InfoCom AB nor the names of its contributors may be + * used to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * @version 1.0 + * @author Mikael Grev, MiG InfoCom AB + * Date: 2006-sep-08 + */ + +/** This class contains static methods to be used by IDE vendors to convert to and from String/API constraints. + * <p> + * <b>Note that {@link LayoutUtil#setDesignTime(boolean)} should be set to <code>true</code> for this class' + * methods to work.</b> + */ +public class IDEUtil +{ + /** A direct reference to the corresponding value for predefined UnitValues in {@link UnitValue}. + */ + public static final UnitValue ZERO = UnitValue.ZERO; + + /** A direct reference to the corresponding value for predefined UnitValues in {@link UnitValue}. + */ + public static final UnitValue TOP = UnitValue.TOP; + + /** A direct reference to the corresponding value for predefined UnitValues in {@link UnitValue}. + */ + public static final UnitValue LEADING = UnitValue.LEADING; + + /** A direct reference to the corresponding value for predefined UnitValues in {@link UnitValue}. + */ + public static final UnitValue LEFT = UnitValue.LEFT; + + /** A direct reference to the corresponding value for predefined UnitValues in {@link UnitValue}. + */ + public static final UnitValue CENTER = UnitValue.CENTER; + + /** A direct reference to the corresponding value for predefined UnitValues in {@link UnitValue}. + */ + public static final UnitValue TRAILING = UnitValue.TRAILING; + + /** A direct reference to the corresponding value for predefined UnitValues in {@link UnitValue}. + */ + public static final UnitValue RIGHT = UnitValue.RIGHT; + + /** A direct reference to the corresponding value for predefined UnitValues in {@link UnitValue}. + */ + public static final UnitValue BOTTOM = UnitValue.BOTTOM; + + /** A direct reference to the corresponding value for predefined UnitValues in {@link UnitValue}. + */ + public static final UnitValue LABEL = UnitValue.LABEL; + + /** A direct reference to the corresponding value for predefined UnitValues in {@link UnitValue}. + */ + public static final UnitValue INF = UnitValue.INF; + + /** A direct reference to the corresponding value for predefined UnitValues in {@link UnitValue}. + */ + public static final UnitValue BASELINE_IDENTITY = UnitValue.BASELINE_IDENTITY; + + private final static String[] X_Y_STRINGS = new String[] {"x", "y", "x2", "y2"}; + + /** Returns the sizes of the rows and gaps for a container. * There will be two arrays returned [0] and [1]. + * <p> + * The first array will be the indexes of the rows where indexes that + * are less than 30000 or larger than 30000 is docking rows. There might be extra docking rows that aren't + * visible but they always have size 0. Non docking indexes will probably always be 0, 1, 2, 3, etc.. + * <p> + * The second array is the sizes of the form:<br> + * <code>[left inset][row size 1][gap 1][row size 2][gap 2][row size n][right inset]</code>. + * <p> + * The returned sizes will be the ones calculated in the last layout cycle. + * @param parentContainer The container to retuern the row sizes and gaps for. In Swing it will be a {@link java.awt.Container} and + * in SWT it will be a {@link org.eclipse.swt.widgets.Composite}. + * @return The sizes or <code>null</code> if {@link LayoutUtil#isDesignTime()} is <code>false</code> or + * <code>parentContainer</code> does not have a MigLayout layout manager. + * The returned sizes will be the ones calculated in the last layout cycle. + * @see LayoutUtil#isDesignTime() + */ + public static int[][] getRowSizes(Object parentContainer) + { + return Grid.getSizesAndIndexes(parentContainer, true); + } + + /** Returns the sizes of the columns and gaps for a container. + * There will be two arrays returned [0] and [1]. + * <p> + * The first array will be the indexes of the columns where indexes that + * are less than 30000 or larger than 30000 is docking columns. There might be extra docking columns that aren't + * visible but they always have size 0. Non docking indexes will probably always be 0, 1, 2, 3, etc.. + * <p> + * The second array is the sizes of the form:<br> + * <code>[top inset][column size 1][gap 1][column size 2][gap 2][column size n][bottom inset]</code>. + * <p> + * The returned sizes will be the ones calculated in the last layout cycle. + * @param parentContainer The container to retuern the column sizes and gaps for. In Swing it will be a {@link java.awt.Container} and + * in SWT it will be a {@link org.eclipse.swt.widgets.Composite}. + * @return The sizes and indexes or <code>null</code> if {@link LayoutUtil#isDesignTime()} is <code>false</code> or + * <code>parentContainer</code> does not have a MigLayout layout manager. + * The returned sizes will be the ones calculated in the last layout cycle. + * @see LayoutUtil#isDesignTime() + */ + public static int[][] getColumnSizes(Object parentContainer) + { + return Grid.getSizesAndIndexes(parentContainer, false); + } + + /** Returns the a constraint string that can be re-parsed to be the exact same AxisConstraint. + * @param ac The axis constraint to return as a constraint string. + * @param asAPI If the returned string should be of API type (e.g. .flowX().gap("rel").align("right")) or + * as a String type (e.g. "flowx, gap rel, right"). + * @param isCols The the constraint should be returned for columns rather than rows. + * @return A String. Never <code>null</code>. + */ + public static final String getConstraintString(AC ac, boolean asAPI, boolean isCols) + { + StringBuffer sb = new StringBuffer(32); + + DimConstraint[] dims = ac.getConstaints(); + BoundSize defGap = isCols ? PlatformDefaults.getGridGapX() : PlatformDefaults.getGridGapY(); + + for (int i = 0; i < dims.length; i++) { + DimConstraint dc = dims[i]; + + addRowDimConstraintString(dc, sb, asAPI); + + if (i < dims.length - 1) { + BoundSize gapAft = dc.getGapAfter(); + BoundSize gapBefNext = dims[i + 1].getGapBefore(); + + if (gapAft != null && gapAft == gapBefNext && gapAft != defGap) { + if (asAPI) { + sb.append(".gap(\"").append(getBS(gapAft)).append("\")"); + } else { + sb.append(getBS(gapAft)); + } + } else { + if (asAPI) + sb.append(".gap()"); + } + } + } + + return sb.toString(); + } + + /** Adds the a constraint string that can be re-parsed to be the exact same DimConstraint. + * @param dc The layout constraint to return as a constraint string. + * @param asAPI If the returned string should be of API type (e.g. .flowX().gap("rel").align("right")) or + * as a String type (e.g. "flowx, gap rel, right"). + */ + private static final void addRowDimConstraintString(DimConstraint dc, StringBuffer sb, boolean asAPI) + { + int gp = dc.getGrowPriority(); + + int firstComma = sb.length(); + + BoundSize size = dc.getSize(); + if (size != null) { + if (asAPI) { + sb.append(".size(\"").append(getBS(size)).append("\")"); + } else { + sb.append(',').append(getBS(size)); + } + } + + if (gp != 100) { + if (asAPI) { + sb.append(".growPrio(").append(gp).append("\")"); + } else { + sb.append(",growprio ").append(gp); + } + } + + Float gw = dc.getGrow(); + if (gw != null) { + String g = gw.floatValue() != 100f ? LayoutUtil.floatToString(gw.floatValue()) : ""; + if (asAPI) { + if (g.length() == 0) { + sb.append(".grow()"); + } else { + sb.append(".grow(\"").append(g).append("\")"); + } + } else { + sb.append(",grow").append(g.length() > 0 ? (" " + g) : ""); + } + } + + int sp = dc.getShrinkPriority(); + if (sp != 100) { + if (asAPI) { + sb.append(".shrinkPrio(").append(sp).append("\")"); + } else { + sb.append(",shrinkprio ").append(sp); + } + } + + Float sw = dc.getShrink(); + if (sw != null && sw.intValue() != 100) { + String s = LayoutUtil.floatToString(sw.floatValue()); + if (asAPI) { + sb.append(".shrink(\"").append(s).append("\")"); + } else { + sb.append(",shrink ").append(s); + } + } + + String eg = dc.getEndGroup(); + if (eg != null) { + if (asAPI) { + sb.append(".endGroup(\"").append(eg).append("\")"); + } else { + sb.append(",endgroup ").append(eg); + } + } + + String sg = dc.getSizeGroup(); + if (sg != null) { + if (asAPI) { + sb.append(".sizeGroup(\"").append(sg).append("\")"); + } else { + sb.append(",sizegroup ").append(sg); + } + } + + UnitValue al = dc.getAlign(); + if (al != null) { + if (asAPI) { + sb.append(".align(\"").append(getUV(al)).append("\")"); + } else { + String s = getUV(al); + String alKw = (s.equals("top") || s.equals("bottom") || s.equals("left") || s.equals("label") || + s.equals("leading") || s.equals("center") || s.equals("trailing") || + s.equals("right") || s.equals("baseline")) ? "" : "align "; + sb.append(',').append(alKw).append(s); + } + } + + if (dc.isNoGrid()) { + if (asAPI) { + sb.append(".noGrid()"); + } else { + sb.append(",nogrid"); + } + } + + if (dc.isFill()) { + if (asAPI) { + sb.append(".fill()"); + } else { + sb.append(",fill"); + } + } + + if (asAPI == false) { + if (sb.length() > firstComma) { + sb.setCharAt(firstComma, '['); + sb.append(']'); + } else { + sb.append("[]"); + } + } + } + + /** Returns the a constraint string that can be re-parsed to be the exact same DimConstraint. + * @param dc The layout constraint to return as a constraint string. + * @param asAPI If the returned string should be of API type (e.g. .flowX().gap("rel").align("right")) or + * as a String type (e.g. "flowx, gap rel, right"). + * @param isHor The the DimConstraint is decoration something horizontal (column or x). + * @param noGrowAdd If <code>true</code> no grow constraints will be added. + * @return A constraint string. Never <code>null</code>. + */ + private static final void addComponentDimConstraintString(DimConstraint dc, StringBuffer sb, boolean asAPI, boolean isHor, boolean noGrowAdd) + { + int gp = dc.getGrowPriority(); + if (gp != 100) { + if (asAPI) { + sb.append(isHor ? ".growPrioX(" : ".growPrioY(").append(gp).append(')'); + } else { + sb.append(isHor ? ",growpriox " : ",growprioy ").append(gp); + } + } + + if (noGrowAdd == false) { + Float gw = dc.getGrow(); + if (gw != null) { + String g = gw.floatValue() != 100f ? LayoutUtil.floatToString(gw.floatValue()) : ""; + if (asAPI) { + sb.append(isHor ? ".growX(" : ".growY(").append(g).append(')'); + } else { + sb.append(isHor ? ",growx" : ",growy").append(g.length() > 0 ? (" " + g) : ""); + } + } + } + + int sp = dc.getShrinkPriority(); + if (sp != 100) { + if (asAPI) { + sb.append(isHor ? ".shrinkPrioX(" : ".shrinkPrioY(").append(sp).append(')'); + } else { + sb.append(isHor ? ",shrinkpriox " : ",shrinkprioy ").append(sp); + } + } + + Float sw = dc.getShrink(); + if (sw != null && sw.intValue() != 100) { + String s = LayoutUtil.floatToString(sw.floatValue()); + if (asAPI) { + sb.append(isHor ? ".shrinkX(" : ".shrinkY(").append(s).append(')'); + } else { + sb.append(isHor ? ",shrinkx " : ",shrinky ").append(s); + } + } + + String eg = dc.getEndGroup(); + if (eg != null) { + if (asAPI) { + sb.append(isHor ? ".endGroupX(\"" : ".endGroupY(\"").append(eg).append("\")"); + } else { + sb.append(isHor ? ",endgroupx " : ",endgroupy ").append(eg); + } + } + + String sg = dc.getSizeGroup(); + if (sg != null) { + if (asAPI) { + sb.append(isHor ? ".sizeGroupX(\"" : ".sizeGroupY(\"").append(sg).append("\")"); + } else { + sb.append(isHor ? ",sizegroupx " : ",sizegroupy ").append(sg); + } + } + + BoundSize size = dc.getSize(); + if (size != null) { + if (size.getPreferred() == null) { + if (size.getMin() == null) { + if (asAPI) { + sb.append(isHor ? ".maxWidth(\"" : ".maxHeight(\"").append(getBS(size)).append("\")"); + } else { + sb.append(isHor ? ",wmax " : ",hmax ").append(getBS(size)); + } + + } else if (size.getMax() == null) { + if (asAPI) { + sb.append(isHor ? ".minWidth(\"" : ".minHeight(\"").append(getBS(size)).append("\")"); + } else { + sb.append(isHor ? ",wmin " : ",hmin ").append(getBS(size)); + } + } + } else { + if (asAPI) { + sb.append(isHor ? ".width(\"" : ".height(\"").append(getBS(size)).append("\")"); + } else { + sb.append(isHor ? ",width " : ",height ").append(getBS(size)); + } + } + } + + UnitValue al = dc.getAlign(); + if (al != null) { + if (asAPI) { + sb.append(isHor ? ".alignX(\"" : ".alignY(\"").append(getUV(al)).append("\")"); + } else { + sb.append(isHor ? ",alignx " : ",aligny ").append(getUV(al)); + } + } + + BoundSize gapBef = dc.getGapBefore(); + BoundSize gapAft= dc.getGapAfter(); + if (gapBef != null || gapAft != null) { + if (asAPI) { + sb.append(isHor ? ".gapX(\"" : ".gapY(\"").append(getBS(gapBef)).append("\", \"").append(getBS(gapAft)).append("\")"); + } else { + sb.append(isHor ? ",gapx " : ",gapy ").append(getBS(gapBef)).append(' ').append(getBS(gapAft)); + } + } + } + + /** Returns the a constraint string that can be re-parsed to be the exact same LayoutConstraint. + * @param cc The component constraint to return as a constraint string. + * @param asAPI If the returned string should be of API type (e.g. .flowX().gap("rel").align("right")) or + * as a String type (e.g. "flowx, gap rel, right"). + * @return A String. Never <code>null</code>. + */ + public static final String getConstraintString(CC cc, boolean asAPI) + { + StringBuffer sb = new StringBuffer(16); + + if (cc.isNewline()) + sb.append(asAPI ? ".newline()" : ",newline"); + + if (cc.isExternal()) + sb.append(asAPI ? ".external()" : ",external"); + + Boolean flowX = cc.getFlowX(); + if (flowX != null) { + if (asAPI) { + sb.append(flowX.booleanValue() ? ".flowX()" : ".flowY()"); + } else { + sb.append(flowX.booleanValue() ? ",flowx" : ",flowy"); + } + } + + UnitValue[] pad = cc.getPadding(); + if (pad != null) { + sb.append(asAPI ? ".pad(\"" : ",pad "); + for (int i = 0; i < pad.length; i++) + sb.append(getUV(pad[i])).append(i < pad.length - 1 ? " " : ""); + if (asAPI) + sb.append("\")"); + } + + UnitValue[] pos = cc.getPos(); + if (pos != null) { + if (cc.isBoundsInGrid()) { + for (int i = 0; i < 4; i++) { + if (pos[i] != null) { + if (asAPI) { + sb.append('.').append(X_Y_STRINGS[i]).append("(\"").append(getUV(pos[i])).append("\")"); + } else { + sb.append(',').append(X_Y_STRINGS[i]).append(getUV(pos[i])); + } + } + } + } else { + sb.append(asAPI ? ".pos(\"" : ",pos "); + int iSz = (pos[2] != null || pos[3] != null) ? 4 : 2; // "pos x y" vs "pos x1 y1 x2 y2". + for (int i = 0; i < iSz; i++) + sb.append(getUV(pos[i])).append(i < iSz - 1 ? " " : ""); + + if (asAPI) + sb.append("\")"); + } + } + + String id = cc.getId(); + if (id != null) { + if (asAPI) { + sb.append(".id(\"").append(id).append("\")"); + } else { + sb.append(",id ").append(id); + } + } + + String tag = cc.getTag(); + if (tag != null) { + if (asAPI) { + sb.append(".tag(\"").append(tag).append("\")"); + } else { + sb.append(",tag ").append(tag); + } + } + + int hideMode = cc.getHideMode(); + if (hideMode >= 0) { + if (asAPI) { + sb.append(".hideMode(").append(hideMode).append(')'); + } else { + sb.append(",hideMode ").append(hideMode); + } + } + + int skip = cc.getSkip(); + if (skip > 0) { + if (asAPI) { + sb.append(".skip(").append(skip).append(')'); + } else { + sb.append(",skip ").append(skip); + } + } + + int split = cc.getSplit(); + if (split > 1) { + String s = split == LayoutUtil.INF ? "" : String.valueOf(split); + if (asAPI) { + sb.append(".split(").append(s).append(')'); + } else { + sb.append(",split ").append(s); + } + } + + int cx = cc.getCellX(); + int cy = cc.getCellY(); + int spanX = cc.getSpanX(); + int spanY = cc.getSpanY(); + if (cx >= 0 && cy >= 0) { + if (asAPI) { + sb.append(".cell(").append(cx).append(", ").append(cy); + if (spanX > 1 || spanY > 1) + sb.append(", ").append(spanX).append(", ").append(spanY); + sb.append(')'); + } else { + sb.append(",cell ").append(cx).append(' ').append(cy); + if (spanX > 1 || spanY > 1) + sb.append(' ').append(spanX).append(' ').append(spanY); + } + } else if (spanX > 1 || spanY > 1) { + if (spanX > 1 && spanY > 1) { + sb.append(asAPI ? ".span(" : ",span ").append(spanX).append(asAPI ? ", " : " ").append(spanY); + } else if (spanX > 1) { + sb.append(asAPI ? ".spanX(" : ",spanx ").append(spanX == LayoutUtil.INF ? "" : (String.valueOf(spanX))); + } else if (spanY > 1) { + sb.append(asAPI ? ".spanY(" : ",spany ").append(spanY == LayoutUtil.INF ? "" : (String.valueOf(spanY))); + } + if (asAPI) + sb.append(')'); + } + + Float pushX = cc.getPushX(); + Float pushY = cc.getPushY(); + if (pushX != null || pushY != null) { + if (pushX != null && pushY != null) { + sb.append(asAPI ? ".push(" : ",push "); + if (pushX != 100.0 || pushY != 100.0) + sb.append(pushX).append(asAPI ? ", " : " ").append(pushY); + } else if (pushX != null) { + sb.append(asAPI ? ".pushX(" : ",pushx ").append(pushX == 100 ? "" : (String.valueOf(pushX))); + } else if (pushY != null) { + sb.append(asAPI ? ".pushY(" : ",pushy ").append(pushY == 100 ? "" : (String.valueOf(pushY))); + } + if (asAPI) + sb.append(')'); + } + + int dock = cc.getDockSide(); + if (dock >= 0) { + String ds = CC.DOCK_SIDES[dock]; + if (asAPI) { + sb.append(".dock").append(Character.toUpperCase(ds.charAt(0))).append(ds.substring(1)).append("()"); + } else { + sb.append(",").append(ds); + } + } + + boolean noGrowAdd = cc.getHorizontal().getGrow() != null && cc.getHorizontal().getGrow().intValue() == 100 && + cc.getVertical().getGrow() != null && cc.getVertical().getGrow().intValue() == 100; + + addComponentDimConstraintString(cc.getHorizontal(), sb, asAPI, true, noGrowAdd); + addComponentDimConstraintString(cc.getVertical(), sb, asAPI, false, noGrowAdd); + if (noGrowAdd) + sb.append(asAPI ? ".grow()" : ",grow"); // Combine ".growX().growY()" into ".grow()". + + if (cc.isWrap()) + sb.append(asAPI ? ".wrap()" : ",wrap"); + + String s = sb.toString(); + return s.length() == 0 || s.charAt(0) != ',' ? s : s.substring(1); + } + + /** Returns the a constraint string that can be re-parsed to be the exact same LayoutConstraint. + * @param lc The layout constraint to return as a constraint string. + * @param asAPI If the returned string should be of API type (e.g. .flowX().gap("rel").align("right")) or + * as a String type (e.g. "flowx, gap rel, right"). + * @return A String. Never <code>null</code>. + */ + public static final String getConstraintString(LC lc, boolean asAPI) + { + StringBuffer sb = new StringBuffer(16); + + if (lc.isFlowX() == false) + sb.append(asAPI ? ".flowY()" : ",flowy"); + + boolean fillX = lc.isFillX(); + boolean fillY = lc.isFillY(); + if (fillX || fillY) { + if (fillX == fillY) { + sb.append(asAPI ? ".fill()" : ",fill"); + } else { + sb.append(asAPI ? (fillX ? ".fillX()" : ".fillY()") : (fillX ? ",fillx" : ",filly")); + } + } + + Boolean leftToRight = lc.getLeftToRight(); + if (leftToRight != null) { + if (asAPI) { + sb.append(".leftToRight(").append(leftToRight).append(')'); + } else { + sb.append(leftToRight.booleanValue() ? ",ltr" : ",rtl"); + } + } + + if (lc.isTopToBottom() == false) + sb.append(asAPI ? ".bottomToTop()" : ",btt"); + + UnitValue[] insets = lc.getInsets(); + if (insets != null) { + String cs = LayoutUtil.getCCString(insets); + if (cs != null) { + if (asAPI) { + sb.append(".insets(\"").append(cs).append("\")"); + } else { + sb.append(",insets ").append(cs); + } + } else { + sb.append(asAPI ? ".insets(\"" : ",insets "); + for (int i = 0; i < insets.length; i++) + sb.append(getUV(insets[i])).append(i < insets.length - 1 ? " " : ""); + if (asAPI) + sb.append("\")"); + } + } + + if (lc.isNoGrid()) + sb.append(asAPI ? ".noGrid()" : ",nogrid"); + + if (lc.isVisualPadding() == false) + sb.append(asAPI ? ".noVisualPadding()" : ",novisualpadding"); + + int hideMode = lc.getHideMode(); + if (hideMode > 0) { + if (asAPI) { + sb.append(".hideMode(").append(hideMode).append(')'); + } else { + sb.append(",hideMode ").append(hideMode); + } + } + + UnitValue alignX = lc.getAlignX(); + UnitValue alignY = lc.getAlignY(); + if (alignX != null || alignY != null) { + if (alignX != null && alignY != null) { + sb.append(asAPI ? ".align(\"" : ",align ").append(getUV(alignX)).append(' ').append(getUV(alignY)); + } else if (alignX != null) { + sb.append(asAPI ? ".alignX(\"" : ",alignx ").append(getUV(alignX)); + } else if (alignY != null) { + sb.append(asAPI ? ".alignY(\"" : ",aligny ").append(getUV(alignY)); + } + if (asAPI) + sb.append("\")"); + } + + BoundSize gridGapX = lc.getGridGapX(); + BoundSize gridGapY = lc.getGridGapY(); + if (gridGapX != null || gridGapY != null) { + if (gridGapX != null && gridGapY != null) { + sb.append(asAPI ? ".gridGap(\"" : ",gap ").append(getBS(gridGapX)).append(' ').append(getBS(gridGapY)); + } else if (gridGapX != null) { + sb.append(asAPI ? ".gridGapX(\"" : ",gapx ").append(getBS(gridGapX)); + } else if (gridGapY != null) { + sb.append(asAPI ? ".gridGapY(\"" : ",gapy ").append(getBS(gridGapY)); + } + if (asAPI) + sb.append("\")"); + } + + int wrapAfter = lc.getWrapAfter(); + if (wrapAfter != LayoutUtil.INF) { + String ws = wrapAfter > 0 ? String.valueOf(wrapAfter) : ""; + if (asAPI) { + sb.append(".wrap(").append(ws).append(')'); + } else { + sb.append(",wrap ").append(ws); + } + } + + int debugMillis = lc.getDebugMillis(); + if (debugMillis > 0) { + if (asAPI) { + sb.append(".debug(").append(debugMillis).append(')'); + } else { + sb.append(",debug ").append(debugMillis); + } + } + + String s = sb.toString(); + return s.length() == 0 || s.charAt(0) != ',' ? s : s.substring(1); + } + + private static String getUV(UnitValue uv) + { + return uv != null ? uv.getConstraintString() : "null"; + } + + private static String getBS(BoundSize bs) + { + return bs != null ? bs.getConstraintString() : "null"; + } +} diff --git a/prototypes/miglayout/net/miginfocom/layout/InCellGapProvider.java b/prototypes/miglayout/net/miginfocom/layout/InCellGapProvider.java index 96367bc1..14fd03c1 100644 --- a/prototypes/miglayout/net/miginfocom/layout/InCellGapProvider.java +++ b/prototypes/miglayout/net/miginfocom/layout/InCellGapProvider.java @@ -1,31 +1,31 @@ -package net.miginfocom.layout;
-
-/** An interfance to implement if you want to decide the gaps between two types of components within the same cell.
- * <p>
- * E.g.:
- *
- * <pre>
- * if (adjacentComp == null || adjacentSide == SwingConstants.LEFT || adjacentSide == SwingConstants.TOP)
- * return null;
- *
- * boolean isHor = (adjacentSide == SwingConstants.LEFT || adjacentSide == SwingConstants.RIGHT);
- *
- * if (adjacentComp.getComponetType(false) == ComponentWrapper.TYPE_LABEL && comp.getComponetType(false) == ComponentWrapper.TYPE_TEXT_FIELD)
- * return isHor ? UNRELATED_Y : UNRELATED_Y;
- *
- * return (adjacentSide == SwingConstants.LEFT || adjacentSide == SwingConstants.RIGHT) ? RELATED_X : RELATED_Y;
- * </pre
- */
-public interface InCellGapProvider
-{
- /** Returns the default gap between two components that <b>are in the same cell</b>.
- * @param comp The component that the gap is for. Never <code>null</code>.
- * @param adjacentComp The adjacent component if any. May be <code>null</code>.
- * @param adjacentSide What side the <code>adjacentComp</code> is on. {@link javax.swing.SwingUtilities#TOP} or
- * {@link javax.swing.SwingUtilities#LEFT} or {@link javax.swing.SwingUtilities#BOTTOM} or {@link javax.swing.SwingUtilities#RIGHT}.
- * @param tag The tag string that the component might be tagged with in the component constraints. May be <code>null</code>.
- * @param isLTR If it is left-to-right.
- * @return The default gap between two components or <code>null</code> if there should be no gap.
- */
- public abstract BoundSize getDefaultGap(ComponentWrapper comp, ComponentWrapper adjacentComp, int adjacentSide, String tag, boolean isLTR);
-}
+package net.miginfocom.layout; + +/** An interfance to implement if you want to decide the gaps between two types of components within the same cell. + * <p> + * E.g.: + * + * <pre> + * if (adjacentComp == null || adjacentSide == SwingConstants.LEFT || adjacentSide == SwingConstants.TOP) + * return null; + * + * boolean isHor = (adjacentSide == SwingConstants.LEFT || adjacentSide == SwingConstants.RIGHT); + * + * if (adjacentComp.getComponetType(false) == ComponentWrapper.TYPE_LABEL && comp.getComponetType(false) == ComponentWrapper.TYPE_TEXT_FIELD) + * return isHor ? UNRELATED_Y : UNRELATED_Y; + * + * return (adjacentSide == SwingConstants.LEFT || adjacentSide == SwingConstants.RIGHT) ? RELATED_X : RELATED_Y; + * </pre + */ +public interface InCellGapProvider +{ + /** Returns the default gap between two components that <b>are in the same cell</b>. + * @param comp The component that the gap is for. Never <code>null</code>. + * @param adjacentComp The adjacent component if any. May be <code>null</code>. + * @param adjacentSide What side the <code>adjacentComp</code> is on. {@link javax.swing.SwingUtilities#TOP} or + * {@link javax.swing.SwingUtilities#LEFT} or {@link javax.swing.SwingUtilities#BOTTOM} or {@link javax.swing.SwingUtilities#RIGHT}. + * @param tag The tag string that the component might be tagged with in the component constraints. May be <code>null</code>. + * @param isLTR If it is left-to-right. + * @return The default gap between two components or <code>null</code> if there should be no gap. + */ + public abstract BoundSize getDefaultGap(ComponentWrapper comp, ComponentWrapper adjacentComp, int adjacentSide, String tag, boolean isLTR); +} diff --git a/prototypes/miglayout/net/miginfocom/layout/LC.java b/prototypes/miglayout/net/miginfocom/layout/LC.java index 82d33191..1c9f7a8c 100644 --- a/prototypes/miglayout/net/miginfocom/layout/LC.java +++ b/prototypes/miglayout/net/miginfocom/layout/LC.java @@ -1,717 +1,717 @@ -package net.miginfocom.layout;
-
-import java.io.*;
-/*
- * License (BSD):
- * ==============
- *
- * Copyright (c) 2004, Mikael Grev, MiG InfoCom AB. (miglayout (at) miginfocom (dot) com)
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification,
- * are permitted provided that the following conditions are met:
- * Redistributions of source code must retain the above copyright notice, this list
- * of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above copyright notice, this
- * list of conditions and the following disclaimer in the documentation and/or other
- * materials provided with the distribution.
- * Neither the name of the MiG InfoCom AB nor the names of its contributors may be
- * used to endorse or promote products derived from this software without specific
- * prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
- * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
- * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
- * OF SUCH DAMAGE.
- *
- * @version 1.0
- * @author Mikael Grev, MiG InfoCom AB
- * Date: 2006-sep-08
- */
-
-/** Contains the constraints for an instance of the {@link LC} layout manager.
- */
-public final class LC implements Externalizable
-{
- // See the corresponding set/get method for documentation of the property!
-
- private int wrapAfter = LayoutUtil.INF;
-
- private Boolean leftToRight = null;
-
- private UnitValue[] insets = null; // Never null elememts but if unset array is null
-
- private UnitValue alignX = null, alignY = null;
-
- private BoundSize gridGapX = null, gridGapY = null;
-
- private int debugMillis = 0;
-
- private int hideMode = 0;
-
- private boolean noCache = false;
-
- private boolean flowX = true;
-
- private boolean fillX = false, fillY = false;
-
- private boolean topToBottom = true;
-
- private boolean noGrid = false;
-
- private boolean visualPadding = true;
-
- /** Empty constructor.
- */
- public LC()
- {
- }
-
- // ************************************************************************
- // * JavaBean get/set methods.
- // ************************************************************************
-
-
- /** If components have sizes or positions linked to the bounds of the parent in some way (as for instance the <code>"%"</code> unit has) the cache
- * must be turned off for the panel. If components does not get the correct or expected size or position try to set this property to <code>true</code>.
- * @return <code>true</code> means no cache and slightly slower layout.
- */
- public boolean isNoCache()
- {
- return noCache;
- }
-
- /** If components have sizes or positions linked to the bounds of the parent in some way (as for instance the <code>"%"</code> unit has) the cache
- * must be turned off for the panel. If components does not get the correct or expected size or position try to set this property to <code>true</code>.
- * @param b <code>true</code> means no cache and slightly slower layout.
- */
- public void setNoCache(boolean b)
- {
- this.noCache = b;
- }
-
- /** If the laid out components' bounds in total is less than the final size of the container these align values will be used to align the components
- * in the parent. <code>null</code> is default and that means top/left alignment. The relative distances between the components will not be affected
- * by this property.
- * @return The current alignment.
- */
- public final UnitValue getAlignX()
- {
- return alignX;
- }
-
- /** If the laid out components' bounds in total is less than the final size of the container these align values will be used to align the components
- * in the parent. <code>null</code> is default and that means top/left alignment. The relative distances between the components will not be affected
- * by this property.
- * @param uv The new alignment. Use {@link ConstraintParser#parseAlignKeywords(String, boolean)} to create the {@link UnitValue}. May be <code>null</code>.
- */
- public final void setAlignX(UnitValue uv)
- {
- this.alignX = uv;
- }
-
- /** If the laid out components' bounds in total is less than the final size of the container these align values will be used to align the components
- * in the parent. <code>null</code> is default and that means top/left alignment. The relative distances between the components will not be affected
- * by this property.
- * @return The current alignment.
- */
- public final UnitValue getAlignY()
- {
- return alignY;
- }
-
- /** If the laid out components' bounds in total is less than the final size of the container these align values will be used to align the components
- * in the parent. <code>null</code> is default and that means top/left alignment. The relative distances between the components will not be affected
- * by this property.
- * @param uv The new alignment. Use {@link ConstraintParser#parseAlignKeywords(String, boolean)} to create the {@link UnitValue}. May be <code>null</code>.
- */
- public final void setAlignY(UnitValue uv)
- {
- this.alignY = uv;
- }
-
- /** If <code>> 0</code> the debug decorations will be repainted every <code>millis</code>. No debug information if <code><= 0</code> (default).
- * @return The current debug repaint interval.
- */
- public final int getDebugMillis()
- {
- return debugMillis;
- }
-
- /** If <code>> 0</code> the debug decorations will be repainted every <code>millis</code>. No debug information if <code><= 0</code> (default).
- * @param millis The new debug repaint interval.
- */
- public final void setDebugMillis(int millis)
- {
- this.debugMillis = millis;
- }
-
- /** If the layout should always claim the whole bounds of the laid out container even if the preferred size is smaller.
- * @return <code>true</code> means fill. <code>false</code> is default.
- */
- public final boolean isFillX()
- {
- return fillX;
- }
-
- /** If the layout should always claim the whole bounds of the laid out container even if the preferred size is smaller.
- * @param b <code>true</code> means fill. <code>false</code> is default.
- */
- public final void setFillX(boolean b)
- {
- this.fillX = b;
- }
-
- /** If the layout should always claim the whole bounds of the laid out container even if the preferred size is smaller.
- * @return <code>true</code> means fill. <code>false</code> is default.
- */
- public final boolean isFillY()
- {
- return fillY;
- }
-
- /** If the layout should always claim the whole bounds of the laid out container even if the preferred size is smaller.
- * @param b <code>true</code> means fill. <code>false</code> is default.
- */
- public final void setFillY(boolean b)
- {
- this.fillY = b;
- }
-
- /** The default flow direction. Normally (which is <code>true</code>) this is horizontal and that means that the "next" component
- * will be put in the cell to the right (or to the left if left-to-right is false).
- * @return <code>true</code> is the default flow horizontally.
- * @see #setLeftToRight(Boolean)
- */
- public final boolean isFlowX()
- {
- return flowX;
- }
-
- /** The default flow direction. Normally (which is <code>true</code>) this is horizontal and that means that the "next" component
- * will be put in the cell to the right (or to the left if left-to-right is false).
- * @param b <code>true</code> is the default flow horizontally.
- * @see #setLeftToRight(Boolean)
- */
- public final void setFlowX(boolean b)
- {
- this.flowX = b;
- }
-
- /** If non-<code>null</code> (<code>null</code> is default) these value will be used as the default gaps between the columns in the grid.
- * @return The default grid gap between columns in the grid. <code>null</code> if the platform default is used.
- */
- public final BoundSize getGridGapX()
- {
- return gridGapX;
- }
-
- /** If non-<code>null</code> (<code>null</code> is default) these value will be used as the default gaps between the columns in the grid.
- * @param x The default grid gap between columns in the grid. If <code>null</code> the platform default is used.
- */
- public final void setGridGapX(BoundSize x)
- {
- this.gridGapX = x;
- }
-
- /** If non-<code>null</code> (<code>null</code> is default) these value will be used as the default gaps between the rows in the grid.
- * @return The default grid gap between rows in the grid. <code>null</code> if the platform default is used.
- */
- public final BoundSize getGridGapY()
- {
- return gridGapY;
- }
-
- /** If non-<code>null</code> (<code>null</code> is default) these value will be used as the default gaps between the rows in the grid.
- * @param y The default grid gap between rows in the grid. If <code>null</code> the platform default is used.
- */
- public final void setGridGapY(BoundSize y)
- {
- this.gridGapY = y;
- }
-
- /** How a component that is hidden (not visible) should be treated by default.
- * @return The mode:<br>
- * 0 == Normal. Bounds will be caclulated as if the component was visible.<br>
- * 1 == If hidden the size will be 0, 0 but the gaps remain.<br>
- * 2 == If hidden the size will be 0, 0 and gaps set to zero.<br>
- * 3 == If hidden the component will be disregarded completely and not take up a cell in the grid..
- */
- public final int getHideMode()
- {
- return hideMode;
- }
-
- /** How a component that is hidden (not visible) should be treated.
- * @param mode The mode:<br>
- * 0 == Normal. Bounds will be caclulated as if the component was visible.<br>
- * 1 == If hidden the size will be 0, 0 but the gaps remain.<br>
- * 2 == If hidden the size will be 0, 0 and gaps set to zero.<br>
- * 3 == If hidden the component will be disregarded completely and not take up a cell in the grid..
- */
- public final void setHideMode(int mode)
- {
- if (mode < 0 || mode > 3)
- throw new IllegalArgumentException("Wrong hideMode: " + mode);
-
- this.hideMode = mode;
- }
-
- /** The insets for the layed out panel. The insets will be an empty space around the components in the panel. <code>null</code> values
- * means that the default panel insets for the platform is used. See {@link PlatformDefaults#setDialogInsets(net.miginfocom.layout.UnitValue, net.miginfocom.layout.UnitValue, net.miginfocom.layout.UnitValue, net.miginfocom.layout.UnitValue)}.
- * @return The insets. Of length 4 (top, left, bottom, right) or <code>null</code>. The elements (1 to 4) may be <code>null</code>. The array is a copy and can be used freely.
- * @see net.miginfocom.layout.ConstraintParser#parseInsets(String, boolean)
- */
- public final UnitValue[] getInsets()
- {
- return insets != null ? new UnitValue[] {insets[0], insets[1], insets[2], insets[3]} : null;
- }
-
- /** The insets for the layed out panel. The insets will be an empty space around the components in the panel. <code>null</code> values
- * means that the default panel insets for the platform is used. See {@link PlatformDefaults#setDialogInsets(net.miginfocom.layout.UnitValue, net.miginfocom.layout.UnitValue, net.miginfocom.layout.UnitValue, net.miginfocom.layout.UnitValue)}.
- * @param ins The new insets. Must be of length 4 (top, left, bottom, right) or <code>null</code>. The elements (1 to 4) may be <code>null</code> to use
- * the platform default for that side. The array is copied for storage.
- * @see net.miginfocom.layout.ConstraintParser#parseInsets(String, boolean)
- */
- public final void setInsets(UnitValue[] ins)
- {
- this.insets = ins != null ? new UnitValue[] {ins[0], ins[1], ins[2], ins[3]} : null;
- }
-
- /** If the layout should be forced to be left-to-right or right-to-left. A value of <code>null</code> is default and
- * means that this will be picked up from the {@link java.util.Locale} that the container being layed out is reporting.
- * @return <code>Boolean.TRUE</code> if force left-to-right. <code>Boolean.FALSE</code> if force tight-to-left. <code>null</code>
- * for the default "let the current Locale decide".
- */
- public final Boolean getLeftToRight()
- {
- return leftToRight;
- }
-
- /** If the layout should be forced to be left-to-right or right-to-left. A value of <code>null</code> is default and
- * means that this will be picked up from the {@link java.util.Locale} that the container being layed out is reporting.
- * @param b <code>Boolean.TRUE</code> to force left-to-right. <code>Boolean.FALSE</code> to force tight-to-left. <code>null</code>
- * for the default "let the current Locale decide".
- */
- public final void setLeftToRight(Boolean b)
- {
- this.leftToRight = b;
- }
-
- /** If the whole layout should be non grid based. It is the same as setting the "nogrid" property on every row/column in the grid.
- * @return <code>true</code> means not grid based. <code>false</code> is default.
- */
- public final boolean isNoGrid()
- {
- return noGrid;
- }
-
- /** If the whole layout should be non grid based. It is the same as setting the "nogrid" property on every row/column in the grid.
- * @param b <code>true</code> means no grid. <code>false</code> is default.
- */
- public final void setNoGrid(boolean b)
- {
- this.noGrid = b;
- }
-
- /** If the layout should go from the default top-to-bottom in the grid instead of the optinal bottom-to-top.
- * @return <code>true</code> for the default top-to-bottom.
- */
- public final boolean isTopToBottom()
- {
- return topToBottom;
- }
-
- /** If the layout should go from the default top-to-bottom in the grid instead of the optinal bottom-to-top.
- * @param b <code>true</code> for the default top-to-bottom.
- */
- public final void setTopToBottom(boolean b)
- {
- this.topToBottom = b;
- }
-
- /** If visual padding should be automatically used and compensated for by this layout instance.
- * @return <code>true</code> if visual padding.
- */
- public final boolean isVisualPadding()
- {
- return visualPadding;
- }
-
- /** If visual padding should be automatically used and compensated for by this layout instance.
- * @param b <code>true</code> turns on visual padding.
- */
- public final void setVisualPadding(boolean b)
- {
- this.visualPadding = b;
- }
-
- /** Returns after what cell the grid should always auto wrap.
- * @return After what cell the grid should always auto wrap. If <code>0</code> the number of columns/rows in the
- * {@link net.miginfocom.layout.AC} is used. <code>LayoutUtil.INF</code> is used for no auto wrap.
- */
- public final int getWrapAfter()
- {
- return wrapAfter;
- }
-
- /** Sets after what cell the grid should always auto wrap.
- * @param count After what cell the grid should always auto wrap. If <code>0</code> the number of columns/rows in the
- * {@link net.miginfocom.layout.AC} is used. <code>LayoutUtil.INF</code> is used for no auto wrap.
- */
- public final void setWrapAfter(int count)
- {
- this.wrapAfter = count;
- }
-
- // ************************************************************************
- // * Builder methods.
- // ************************************************************************
-
- /** Sets a wrap after the number of columns/rows that is defined in the {@link net.miginfocom.layout.AC}.
- * <p>
- * Same functionality as {@link #setWrapAfter(int 0)} only this method returns <code>this</code> for chaining multiple calls.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @return <code>this</code> so it is possible to chain calls. E.g. <code>new LayoutConstraint().noGrid().gap().fill()</code>.
- */
- public final LC wrap()
- {
- setWrapAfter(0);
- return this;
- }
-
- /** Same functionality as {@link #setWrapAfter(int)} only this method returns <code>this</code> for chaining multiple calls.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @param count After what cell the grid should always auto wrap. If <code>0</code> the number of columns/rows in the
- * @return <code>this</code> so it is possible to chain calls. E.g. <code>new LayoutConstraint().noGrid().gap().fill()</code>.
- */
- public final LC wrapAfter(int count)
- {
- setWrapAfter(count);
- return this;
- }
-
- /** Same functionality as {@link #setNoCache(boolean true)} only this method returns <code>this</code> for chaining multiple calls.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @return <code>this</code> so it is possible to chain calls. E.g. <code>new LayoutConstraint().noGrid().gap().fill()</code>.
- */
- public final LC noCache()
- {
- setNoCache(true);
- return this;
- }
-
- /** Same functionality as {@link #setFlowX(boolean false)} only this method returns <code>this</code> for chaining multiple calls.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @return <code>this</code> so it is possible to chain calls. E.g. <code>new LayoutConstraint().noGrid().gap().fill()</code>.
- */
- public final LC flowY()
- {
- setFlowX(false);
- return this;
- }
-
- /** Same functionality as {@link #setFlowX(boolean true)} only this method returns <code>this</code> for chaining multiple calls.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @return <code>this</code> so it is possible to chain calls. E.g. <code>new LayoutConstraint().noGrid().gap().fill()</code>.
- */
- public final LC flowX()
- {
- setFlowX(true);
- return this;
- }
-
- /** Same functionality as {@link #setFillX(boolean true)} and {@link #setFillY(boolean true)} conmbined.T his method returns
- * <code>this</code> for chaining multiple calls.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @return <code>this</code> so it is possible to chain calls. E.g. <code>new LayoutConstraint().noGrid().gap().fill()</code>.
- */
- public final LC fill()
- {
- setFillX(true);
- setFillY(true);
- return this;
- }
-
- /** Same functionality as {@link #setFillX(boolean true)} only this method returns <code>this</code> for chaining multiple calls.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @return <code>this</code> so it is possible to chain calls. E.g. <code>new LayoutConstraint().noGrid().gap().fill()</code>.
- */
- public final LC fillX()
- {
- setFillX(true);
- return this;
- }
-
- /** Same functionality as {@link #setFillY(boolean true)} only this method returns <code>this</code> for chaining multiple calls.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @return <code>this</code> so it is possible to chain calls. E.g. <code>new LayoutConstraint().noGrid().gap().fill()</code>.
- */
- public final LC fillY()
- {
- setFillY(true);
- return this;
- }
-
- /** Same functionality as {@link #setLeftToRight(Boolean)} only this method returns <code>this</code> for chaining multiple calls.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @param b <code>true</code> for forcing left-to-right. <code>false</code> for forcing right-to-left.
- * @return <code>this</code> so it is possible to chain calls. E.g. <code>new LayoutConstraint().noGrid().gap().fill()</code>.
- */
- public final LC leftToRight(boolean b)
- {
- setLeftToRight(b ? Boolean.TRUE : Boolean.FALSE); // Not .valueOf du to retroweaver...
- return this;
- }
-
- /** Same functionality as {@link #setTopToBottom(boolean false)} only this method returns <code>this</code> for chaining multiple calls.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @return <code>this</code> so it is possible to chain calls. E.g. <code>new LayoutConstraint().noGrid().gap().fill()</code>.
- */
- public final LC bottomToTop()
- {
- setTopToBottom(false);
- return this;
- }
-
- /** Same functionality as {@link #setNoGrid(boolean true)} only this method returns <code>this</code> for chaining multiple calls.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @return <code>this</code> so it is possible to chain calls. E.g. <code>new LayoutConstraint().noGrid().gap().fill()</code>.
- */
- public final LC noGrid()
- {
- setNoGrid(true);
- return this;
- }
-
- /** Same functionality as {@link #setVisualPadding(boolean false)} only this method returns <code>this</code> for chaining multiple calls.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @return <code>this</code> so it is possible to chain calls. E.g. <code>new LayoutConstraint().noGrid().gap().fill()</code>.
- */
- public final LC noVisualPadding()
- {
- setVisualPadding(false);
- return this;
- }
-
- /** Sets the same inset (expressed as a <code>UnitValue</code>, e.g. "10px" or "20mm") all around.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @param allSides The unit value to set for all sides. May be <code>null</code> which means that the default panel insets
- * for the platform is used.
- * @return <code>this</code> so it is possible to chain calls. E.g. <code>new LayoutConstraint().noGrid().gap().fill()</code>.
- * @see #setInsets(UnitValue[])
- */
- public final LC insetsAll(String allSides)
- {
- UnitValue insH = ConstraintParser.parseUnitValue(allSides, true);
- UnitValue insV = ConstraintParser.parseUnitValue(allSides, false);
- insets = new UnitValue[] {insV, insH, insV, insH}; // No setter to avoid copy again
- return this;
- }
-
- /** Same functionality as <code>setInsets(ConstraintParser.parseInsets(s, true))</code>. This method returns <code>this</code>
- * for chaining multiple calls.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @param s The string to parse. E.g. "10 10 10 10" or "20". If less than 4 groups the last will be used for the missing.
- * @return <code>this</code> so it is possible to chain calls. E.g. <code>new LayoutConstraint().noGrid().gap().fill()</code>.
- * @see #setInsets(UnitValue[])
- */
- public final LC insets(String s)
- {
- insets = ConstraintParser.parseInsets(s, true);
- return this;
- }
-
- /** Sets the different insets (expressed as a <code>UnitValue</code>s, e.g. "10px" or "20mm") for the corresponding sides.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @param top The top inset. E.g. "10px" or "10mm" or "related". May be <code>null</code> in which case the default inset for this
- * side for the platform will be used.
- * @param left The left inset. E.g. "10px" or "10mm" or "related". May be <code>null</code> in which case the default inset for this
- * side for the platform will be used.
- * @param bottom The bottom inset. E.g. "10px" or "10mm" or "related". May be <code>null</code> in which case the default inset for this
- * side for the platform will be used.
- * @param right The right inset. E.g. "10px" or "10mm" or "related". May be <code>null</code> in which case the default inset for this
- * side for the platform will be used.
- * @return <code>this</code> so it is possible to chain calls. E.g. <code>new LayoutConstraint().noGrid().gap().fill()</code>.
- * @see #setInsets(UnitValue[])
- */
- public final LC insets(String top, String left, String bottom, String right)
- {
- insets = new UnitValue[] { // No setter to avoid copy again
- ConstraintParser.parseUnitValue(top, false),
- ConstraintParser.parseUnitValue(left, true),
- ConstraintParser.parseUnitValue(bottom, false),
- ConstraintParser.parseUnitValue(right, true)};
- return this;
- }
-
- /** Same functionality as <code>setAlignX(ConstraintParser.parseUnitValueOrAlign(unitValue, true))</code> only this method returns <code>this</code>
- * for chaining multiple calls.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @param align The align keyword or for instance "100px". E.g "left", "right", "leading" or "trailing".
- * @return <code>this</code> so it is possible to chain calls. E.g. <code>new LayoutConstraint().noGrid().gap().fill()</code>.
- * @see #setAlignX(UnitValue)
- */
- public final LC alignX(String align)
- {
- setAlignX(ConstraintParser.parseUnitValueOrAlign(align, true, null));
- return this;
- }
-
- /** Same functionality as <code>setAlignY(ConstraintParser.parseUnitValueOrAlign(align, false))</code> only this method returns <code>this</code> for chaining multiple calls.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @param align The align keyword or for instance "100px". E.g "top" or "bottom".
- * @return <code>this</code> so it is possible to chain calls. E.g. <code>new LayoutConstraint().noGrid().gap().fill()</code>.
- * @see #setAlignY(UnitValue)
- */
- public final LC alignY(String align)
- {
- setAlignY(ConstraintParser.parseUnitValueOrAlign(align, false, null));
- return this;
- }
-
- /** Sets both the alignX and alignY as the same time.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @param ax The align keyword or for instance "100px". E.g "left", "right", "leading" or "trailing".
- * @param ay The align keyword or for instance "100px". E.g "top" or "bottom".
- * @return <code>this</code> so it is possible to chain calls. E.g. <code>new LayoutConstraint().noGrid().gap().fill()</code>.
- * @see #alignX(String)
- * @see #alignY(String)
- */
- public final LC align(String ax, String ay)
- {
- if (ax != null)
- alignX(ax);
-
- if (ay != null)
- alignY(ay);
-
- return this;
- }
-
- /** Same functionality as <code>setGridGapX(ConstraintParser.parseBoundSize(boundsSize, true, true))</code> only this method
- * returns <code>this</code> for chaining multiple calls.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @param boundsSize The <code>BoundSize</code> of the gap. This is a minimum and/or preferred and/or maximum size. E.g.
- * <code>"50:100:200"</code> or <code>"100px"</code>.
- * @return <code>this</code> so it is possible to chain calls. E.g. <code>new LayoutConstraint().noGrid().gap().fill()</code>.
- * @see #setGridGapX(BoundSize)
- */
- public final LC gridGapX(String boundsSize)
- {
- setGridGapX(ConstraintParser.parseBoundSize(boundsSize, true, true));
- return this;
- }
-
- /** Same functionality as <code>setGridGapY(ConstraintParser.parseBoundSize(boundsSize, true, false))</code> only this method
- * returns <code>this</code> for chaining multiple calls.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @param boundsSize The <code>BoundSize</code> of the gap. This is a minimum and/or preferred and/or maximum size. E.g.
- * <code>"50:100:200"</code> or <code>"100px"</code>.
- * @return <code>this</code> so it is possible to chain calls. E.g. <code>new LayoutConstraint().noGrid().gap().fill()</code>.
- * @see #setGridGapY(BoundSize)
- */
- public final LC gridGapY(String boundsSize)
- {
- setGridGapY(ConstraintParser.parseBoundSize(boundsSize, true, false));
- return this;
- }
-
- /** Sets both grid gaps at the same time. see {@link #gridGapX(String)} and {@link #gridGapY(String)}.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @param gapx The <code>BoundSize</code> of the gap. This is a minimum and/or preferred and/or maximum size. E.g.
- * <code>"50:100:200"</code> or <code>"100px"</code>.
- * @param gapy The <code>BoundSize</code> of the gap. This is a minimum and/or preferred and/or maximum size. E.g.
- * <code>"50:100:200"</code> or <code>"100px"</code>.
- * @return <code>this</code> so it is possible to chain calls. E.g. <code>new LayoutConstraint().noGrid().gap().fill()</code>.
- * @see #gridGapX(String)
- * @see #gridGapY(String)
- */
- public final LC gridGap(String gapx, String gapy)
- {
- if (gapx != null)
- gridGapX(gapx);
-
- if (gapy != null)
- gridGapY(gapy);
-
- return this;
- }
-
- /** Same functionality as {@link #setDebugMillis(int repaintMillis)} only this method returns <code>this</code> for chaining multiple calls.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @param repaintMillis The new debug repaint interval.
- * @return <code>this</code> so it is possible to chain calls. E.g. <code>new LayoutConstraint().noGrid().gap().fill()</code>.
- * @see #setDebugMillis(int)
- */
- public final LC debug(int repaintMillis)
- {
- setDebugMillis(repaintMillis);
- return this;
- }
-
- /** Same functionality as {@link #setHideMode(int mode)} only this method returns <code>this</code> for chaining multiple calls.
- * <p>
- * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
- * @param mode The mode:<br>
- * 0 == Normal. Bounds will be caclulated as if the component was visible.<br>
- * 1 == If hidden the size will be 0, 0 but the gaps remain.<br>
- * 2 == If hidden the size will be 0, 0 and gaps set to zero.<br>
- * 3 == If hidden the component will be disregarded completely and not take up a cell in the grid..
- * @return <code>this</code> so it is possible to chain calls. E.g. <code>new LayoutConstraint().noGrid().gap().fill()</code>.
- * @see #setHideMode(int)
- */
- public final LC hideMode(int mode)
- {
- setHideMode(mode);
- return this;
- }
-
- // ************************************************
- // Persistence Delegate and Serializable combined.
- // ************************************************
-
- private Object readResolve() throws ObjectStreamException
- {
- return LayoutUtil.getSerializedObject(this);
- }
-
- public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException
- {
- LayoutUtil.setSerializedObject(this, LayoutUtil.readAsXML(in));
- }
-
- public void writeExternal(ObjectOutput out) throws IOException
- {
- if (getClass() == LC.class)
- LayoutUtil.writeAsXML(out, this);
- }
-}
+package net.miginfocom.layout; + +import java.io.*; +/* + * License (BSD): + * ============== + * + * Copyright (c) 2004, Mikael Grev, MiG InfoCom AB. (miglayout (at) miginfocom (dot) com) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright notice, this list + * of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * Neither the name of the MiG InfoCom AB nor the names of its contributors may be + * used to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * @version 1.0 + * @author Mikael Grev, MiG InfoCom AB + * Date: 2006-sep-08 + */ + +/** Contains the constraints for an instance of the {@link LC} layout manager. + */ +public final class LC implements Externalizable +{ + // See the corresponding set/get method for documentation of the property! + + private int wrapAfter = LayoutUtil.INF; + + private Boolean leftToRight = null; + + private UnitValue[] insets = null; // Never null elememts but if unset array is null + + private UnitValue alignX = null, alignY = null; + + private BoundSize gridGapX = null, gridGapY = null; + + private int debugMillis = 0; + + private int hideMode = 0; + + private boolean noCache = false; + + private boolean flowX = true; + + private boolean fillX = false, fillY = false; + + private boolean topToBottom = true; + + private boolean noGrid = false; + + private boolean visualPadding = true; + + /** Empty constructor. + */ + public LC() + { + } + + // ************************************************************************ + // * JavaBean get/set methods. + // ************************************************************************ + + + /** If components have sizes or positions linked to the bounds of the parent in some way (as for instance the <code>"%"</code> unit has) the cache + * must be turned off for the panel. If components does not get the correct or expected size or position try to set this property to <code>true</code>. + * @return <code>true</code> means no cache and slightly slower layout. + */ + public boolean isNoCache() + { + return noCache; + } + + /** If components have sizes or positions linked to the bounds of the parent in some way (as for instance the <code>"%"</code> unit has) the cache + * must be turned off for the panel. If components does not get the correct or expected size or position try to set this property to <code>true</code>. + * @param b <code>true</code> means no cache and slightly slower layout. + */ + public void setNoCache(boolean b) + { + this.noCache = b; + } + + /** If the laid out components' bounds in total is less than the final size of the container these align values will be used to align the components + * in the parent. <code>null</code> is default and that means top/left alignment. The relative distances between the components will not be affected + * by this property. + * @return The current alignment. + */ + public final UnitValue getAlignX() + { + return alignX; + } + + /** If the laid out components' bounds in total is less than the final size of the container these align values will be used to align the components + * in the parent. <code>null</code> is default and that means top/left alignment. The relative distances between the components will not be affected + * by this property. + * @param uv The new alignment. Use {@link ConstraintParser#parseAlignKeywords(String, boolean)} to create the {@link UnitValue}. May be <code>null</code>. + */ + public final void setAlignX(UnitValue uv) + { + this.alignX = uv; + } + + /** If the laid out components' bounds in total is less than the final size of the container these align values will be used to align the components + * in the parent. <code>null</code> is default and that means top/left alignment. The relative distances between the components will not be affected + * by this property. + * @return The current alignment. + */ + public final UnitValue getAlignY() + { + return alignY; + } + + /** If the laid out components' bounds in total is less than the final size of the container these align values will be used to align the components + * in the parent. <code>null</code> is default and that means top/left alignment. The relative distances between the components will not be affected + * by this property. + * @param uv The new alignment. Use {@link ConstraintParser#parseAlignKeywords(String, boolean)} to create the {@link UnitValue}. May be <code>null</code>. + */ + public final void setAlignY(UnitValue uv) + { + this.alignY = uv; + } + + /** If <code>> 0</code> the debug decorations will be repainted every <code>millis</code>. No debug information if <code><= 0</code> (default). + * @return The current debug repaint interval. + */ + public final int getDebugMillis() + { + return debugMillis; + } + + /** If <code>> 0</code> the debug decorations will be repainted every <code>millis</code>. No debug information if <code><= 0</code> (default). + * @param millis The new debug repaint interval. + */ + public final void setDebugMillis(int millis) + { + this.debugMillis = millis; + } + + /** If the layout should always claim the whole bounds of the laid out container even if the preferred size is smaller. + * @return <code>true</code> means fill. <code>false</code> is default. + */ + public final boolean isFillX() + { + return fillX; + } + + /** If the layout should always claim the whole bounds of the laid out container even if the preferred size is smaller. + * @param b <code>true</code> means fill. <code>false</code> is default. + */ + public final void setFillX(boolean b) + { + this.fillX = b; + } + + /** If the layout should always claim the whole bounds of the laid out container even if the preferred size is smaller. + * @return <code>true</code> means fill. <code>false</code> is default. + */ + public final boolean isFillY() + { + return fillY; + } + + /** If the layout should always claim the whole bounds of the laid out container even if the preferred size is smaller. + * @param b <code>true</code> means fill. <code>false</code> is default. + */ + public final void setFillY(boolean b) + { + this.fillY = b; + } + + /** The default flow direction. Normally (which is <code>true</code>) this is horizontal and that means that the "next" component + * will be put in the cell to the right (or to the left if left-to-right is false). + * @return <code>true</code> is the default flow horizontally. + * @see #setLeftToRight(Boolean) + */ + public final boolean isFlowX() + { + return flowX; + } + + /** The default flow direction. Normally (which is <code>true</code>) this is horizontal and that means that the "next" component + * will be put in the cell to the right (or to the left if left-to-right is false). + * @param b <code>true</code> is the default flow horizontally. + * @see #setLeftToRight(Boolean) + */ + public final void setFlowX(boolean b) + { + this.flowX = b; + } + + /** If non-<code>null</code> (<code>null</code> is default) these value will be used as the default gaps between the columns in the grid. + * @return The default grid gap between columns in the grid. <code>null</code> if the platform default is used. + */ + public final BoundSize getGridGapX() + { + return gridGapX; + } + + /** If non-<code>null</code> (<code>null</code> is default) these value will be used as the default gaps between the columns in the grid. + * @param x The default grid gap between columns in the grid. If <code>null</code> the platform default is used. + */ + public final void setGridGapX(BoundSize x) + { + this.gridGapX = x; + } + + /** If non-<code>null</code> (<code>null</code> is default) these value will be used as the default gaps between the rows in the grid. + * @return The default grid gap between rows in the grid. <code>null</code> if the platform default is used. + */ + public final BoundSize getGridGapY() + { + return gridGapY; + } + + /** If non-<code>null</code> (<code>null</code> is default) these value will be used as the default gaps between the rows in the grid. + * @param y The default grid gap between rows in the grid. If <code>null</code> the platform default is used. + */ + public final void setGridGapY(BoundSize y) + { + this.gridGapY = y; + } + + /** How a component that is hidden (not visible) should be treated by default. + * @return The mode:<br> + * 0 == Normal. Bounds will be caclulated as if the component was visible.<br> + * 1 == If hidden the size will be 0, 0 but the gaps remain.<br> + * 2 == If hidden the size will be 0, 0 and gaps set to zero.<br> + * 3 == If hidden the component will be disregarded completely and not take up a cell in the grid.. + */ + public final int getHideMode() + { + return hideMode; + } + + /** How a component that is hidden (not visible) should be treated. + * @param mode The mode:<br> + * 0 == Normal. Bounds will be caclulated as if the component was visible.<br> + * 1 == If hidden the size will be 0, 0 but the gaps remain.<br> + * 2 == If hidden the size will be 0, 0 and gaps set to zero.<br> + * 3 == If hidden the component will be disregarded completely and not take up a cell in the grid.. + */ + public final void setHideMode(int mode) + { + if (mode < 0 || mode > 3) + throw new IllegalArgumentException("Wrong hideMode: " + mode); + + this.hideMode = mode; + } + + /** The insets for the layed out panel. The insets will be an empty space around the components in the panel. <code>null</code> values + * means that the default panel insets for the platform is used. See {@link PlatformDefaults#setDialogInsets(net.miginfocom.layout.UnitValue, net.miginfocom.layout.UnitValue, net.miginfocom.layout.UnitValue, net.miginfocom.layout.UnitValue)}. + * @return The insets. Of length 4 (top, left, bottom, right) or <code>null</code>. The elements (1 to 4) may be <code>null</code>. The array is a copy and can be used freely. + * @see net.miginfocom.layout.ConstraintParser#parseInsets(String, boolean) + */ + public final UnitValue[] getInsets() + { + return insets != null ? new UnitValue[] {insets[0], insets[1], insets[2], insets[3]} : null; + } + + /** The insets for the layed out panel. The insets will be an empty space around the components in the panel. <code>null</code> values + * means that the default panel insets for the platform is used. See {@link PlatformDefaults#setDialogInsets(net.miginfocom.layout.UnitValue, net.miginfocom.layout.UnitValue, net.miginfocom.layout.UnitValue, net.miginfocom.layout.UnitValue)}. + * @param ins The new insets. Must be of length 4 (top, left, bottom, right) or <code>null</code>. The elements (1 to 4) may be <code>null</code> to use + * the platform default for that side. The array is copied for storage. + * @see net.miginfocom.layout.ConstraintParser#parseInsets(String, boolean) + */ + public final void setInsets(UnitValue[] ins) + { + this.insets = ins != null ? new UnitValue[] {ins[0], ins[1], ins[2], ins[3]} : null; + } + + /** If the layout should be forced to be left-to-right or right-to-left. A value of <code>null</code> is default and + * means that this will be picked up from the {@link java.util.Locale} that the container being layed out is reporting. + * @return <code>Boolean.TRUE</code> if force left-to-right. <code>Boolean.FALSE</code> if force tight-to-left. <code>null</code> + * for the default "let the current Locale decide". + */ + public final Boolean getLeftToRight() + { + return leftToRight; + } + + /** If the layout should be forced to be left-to-right or right-to-left. A value of <code>null</code> is default and + * means that this will be picked up from the {@link java.util.Locale} that the container being layed out is reporting. + * @param b <code>Boolean.TRUE</code> to force left-to-right. <code>Boolean.FALSE</code> to force tight-to-left. <code>null</code> + * for the default "let the current Locale decide". + */ + public final void setLeftToRight(Boolean b) + { + this.leftToRight = b; + } + + /** If the whole layout should be non grid based. It is the same as setting the "nogrid" property on every row/column in the grid. + * @return <code>true</code> means not grid based. <code>false</code> is default. + */ + public final boolean isNoGrid() + { + return noGrid; + } + + /** If the whole layout should be non grid based. It is the same as setting the "nogrid" property on every row/column in the grid. + * @param b <code>true</code> means no grid. <code>false</code> is default. + */ + public final void setNoGrid(boolean b) + { + this.noGrid = b; + } + + /** If the layout should go from the default top-to-bottom in the grid instead of the optinal bottom-to-top. + * @return <code>true</code> for the default top-to-bottom. + */ + public final boolean isTopToBottom() + { + return topToBottom; + } + + /** If the layout should go from the default top-to-bottom in the grid instead of the optinal bottom-to-top. + * @param b <code>true</code> for the default top-to-bottom. + */ + public final void setTopToBottom(boolean b) + { + this.topToBottom = b; + } + + /** If visual padding should be automatically used and compensated for by this layout instance. + * @return <code>true</code> if visual padding. + */ + public final boolean isVisualPadding() + { + return visualPadding; + } + + /** If visual padding should be automatically used and compensated for by this layout instance. + * @param b <code>true</code> turns on visual padding. + */ + public final void setVisualPadding(boolean b) + { + this.visualPadding = b; + } + + /** Returns after what cell the grid should always auto wrap. + * @return After what cell the grid should always auto wrap. If <code>0</code> the number of columns/rows in the + * {@link net.miginfocom.layout.AC} is used. <code>LayoutUtil.INF</code> is used for no auto wrap. + */ + public final int getWrapAfter() + { + return wrapAfter; + } + + /** Sets after what cell the grid should always auto wrap. + * @param count After what cell the grid should always auto wrap. If <code>0</code> the number of columns/rows in the + * {@link net.miginfocom.layout.AC} is used. <code>LayoutUtil.INF</code> is used for no auto wrap. + */ + public final void setWrapAfter(int count) + { + this.wrapAfter = count; + } + + // ************************************************************************ + // * Builder methods. + // ************************************************************************ + + /** Sets a wrap after the number of columns/rows that is defined in the {@link net.miginfocom.layout.AC}. + * <p> + * Same functionality as {@link #setWrapAfter(int 0)} only this method returns <code>this</code> for chaining multiple calls. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @return <code>this</code> so it is possible to chain calls. E.g. <code>new LayoutConstraint().noGrid().gap().fill()</code>. + */ + public final LC wrap() + { + setWrapAfter(0); + return this; + } + + /** Same functionality as {@link #setWrapAfter(int)} only this method returns <code>this</code> for chaining multiple calls. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @param count After what cell the grid should always auto wrap. If <code>0</code> the number of columns/rows in the + * @return <code>this</code> so it is possible to chain calls. E.g. <code>new LayoutConstraint().noGrid().gap().fill()</code>. + */ + public final LC wrapAfter(int count) + { + setWrapAfter(count); + return this; + } + + /** Same functionality as {@link #setNoCache(boolean true)} only this method returns <code>this</code> for chaining multiple calls. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @return <code>this</code> so it is possible to chain calls. E.g. <code>new LayoutConstraint().noGrid().gap().fill()</code>. + */ + public final LC noCache() + { + setNoCache(true); + return this; + } + + /** Same functionality as {@link #setFlowX(boolean false)} only this method returns <code>this</code> for chaining multiple calls. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @return <code>this</code> so it is possible to chain calls. E.g. <code>new LayoutConstraint().noGrid().gap().fill()</code>. + */ + public final LC flowY() + { + setFlowX(false); + return this; + } + + /** Same functionality as {@link #setFlowX(boolean true)} only this method returns <code>this</code> for chaining multiple calls. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @return <code>this</code> so it is possible to chain calls. E.g. <code>new LayoutConstraint().noGrid().gap().fill()</code>. + */ + public final LC flowX() + { + setFlowX(true); + return this; + } + + /** Same functionality as {@link #setFillX(boolean true)} and {@link #setFillY(boolean true)} conmbined.T his method returns + * <code>this</code> for chaining multiple calls. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @return <code>this</code> so it is possible to chain calls. E.g. <code>new LayoutConstraint().noGrid().gap().fill()</code>. + */ + public final LC fill() + { + setFillX(true); + setFillY(true); + return this; + } + + /** Same functionality as {@link #setFillX(boolean true)} only this method returns <code>this</code> for chaining multiple calls. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @return <code>this</code> so it is possible to chain calls. E.g. <code>new LayoutConstraint().noGrid().gap().fill()</code>. + */ + public final LC fillX() + { + setFillX(true); + return this; + } + + /** Same functionality as {@link #setFillY(boolean true)} only this method returns <code>this</code> for chaining multiple calls. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @return <code>this</code> so it is possible to chain calls. E.g. <code>new LayoutConstraint().noGrid().gap().fill()</code>. + */ + public final LC fillY() + { + setFillY(true); + return this; + } + + /** Same functionality as {@link #setLeftToRight(Boolean)} only this method returns <code>this</code> for chaining multiple calls. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @param b <code>true</code> for forcing left-to-right. <code>false</code> for forcing right-to-left. + * @return <code>this</code> so it is possible to chain calls. E.g. <code>new LayoutConstraint().noGrid().gap().fill()</code>. + */ + public final LC leftToRight(boolean b) + { + setLeftToRight(b ? Boolean.TRUE : Boolean.FALSE); // Not .valueOf du to retroweaver... + return this; + } + + /** Same functionality as {@link #setTopToBottom(boolean false)} only this method returns <code>this</code> for chaining multiple calls. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @return <code>this</code> so it is possible to chain calls. E.g. <code>new LayoutConstraint().noGrid().gap().fill()</code>. + */ + public final LC bottomToTop() + { + setTopToBottom(false); + return this; + } + + /** Same functionality as {@link #setNoGrid(boolean true)} only this method returns <code>this</code> for chaining multiple calls. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @return <code>this</code> so it is possible to chain calls. E.g. <code>new LayoutConstraint().noGrid().gap().fill()</code>. + */ + public final LC noGrid() + { + setNoGrid(true); + return this; + } + + /** Same functionality as {@link #setVisualPadding(boolean false)} only this method returns <code>this</code> for chaining multiple calls. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @return <code>this</code> so it is possible to chain calls. E.g. <code>new LayoutConstraint().noGrid().gap().fill()</code>. + */ + public final LC noVisualPadding() + { + setVisualPadding(false); + return this; + } + + /** Sets the same inset (expressed as a <code>UnitValue</code>, e.g. "10px" or "20mm") all around. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @param allSides The unit value to set for all sides. May be <code>null</code> which means that the default panel insets + * for the platform is used. + * @return <code>this</code> so it is possible to chain calls. E.g. <code>new LayoutConstraint().noGrid().gap().fill()</code>. + * @see #setInsets(UnitValue[]) + */ + public final LC insetsAll(String allSides) + { + UnitValue insH = ConstraintParser.parseUnitValue(allSides, true); + UnitValue insV = ConstraintParser.parseUnitValue(allSides, false); + insets = new UnitValue[] {insV, insH, insV, insH}; // No setter to avoid copy again + return this; + } + + /** Same functionality as <code>setInsets(ConstraintParser.parseInsets(s, true))</code>. This method returns <code>this</code> + * for chaining multiple calls. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @param s The string to parse. E.g. "10 10 10 10" or "20". If less than 4 groups the last will be used for the missing. + * @return <code>this</code> so it is possible to chain calls. E.g. <code>new LayoutConstraint().noGrid().gap().fill()</code>. + * @see #setInsets(UnitValue[]) + */ + public final LC insets(String s) + { + insets = ConstraintParser.parseInsets(s, true); + return this; + } + + /** Sets the different insets (expressed as a <code>UnitValue</code>s, e.g. "10px" or "20mm") for the corresponding sides. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @param top The top inset. E.g. "10px" or "10mm" or "related". May be <code>null</code> in which case the default inset for this + * side for the platform will be used. + * @param left The left inset. E.g. "10px" or "10mm" or "related". May be <code>null</code> in which case the default inset for this + * side for the platform will be used. + * @param bottom The bottom inset. E.g. "10px" or "10mm" or "related". May be <code>null</code> in which case the default inset for this + * side for the platform will be used. + * @param right The right inset. E.g. "10px" or "10mm" or "related". May be <code>null</code> in which case the default inset for this + * side for the platform will be used. + * @return <code>this</code> so it is possible to chain calls. E.g. <code>new LayoutConstraint().noGrid().gap().fill()</code>. + * @see #setInsets(UnitValue[]) + */ + public final LC insets(String top, String left, String bottom, String right) + { + insets = new UnitValue[] { // No setter to avoid copy again + ConstraintParser.parseUnitValue(top, false), + ConstraintParser.parseUnitValue(left, true), + ConstraintParser.parseUnitValue(bottom, false), + ConstraintParser.parseUnitValue(right, true)}; + return this; + } + + /** Same functionality as <code>setAlignX(ConstraintParser.parseUnitValueOrAlign(unitValue, true))</code> only this method returns <code>this</code> + * for chaining multiple calls. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @param align The align keyword or for instance "100px". E.g "left", "right", "leading" or "trailing". + * @return <code>this</code> so it is possible to chain calls. E.g. <code>new LayoutConstraint().noGrid().gap().fill()</code>. + * @see #setAlignX(UnitValue) + */ + public final LC alignX(String align) + { + setAlignX(ConstraintParser.parseUnitValueOrAlign(align, true, null)); + return this; + } + + /** Same functionality as <code>setAlignY(ConstraintParser.parseUnitValueOrAlign(align, false))</code> only this method returns <code>this</code> for chaining multiple calls. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @param align The align keyword or for instance "100px". E.g "top" or "bottom". + * @return <code>this</code> so it is possible to chain calls. E.g. <code>new LayoutConstraint().noGrid().gap().fill()</code>. + * @see #setAlignY(UnitValue) + */ + public final LC alignY(String align) + { + setAlignY(ConstraintParser.parseUnitValueOrAlign(align, false, null)); + return this; + } + + /** Sets both the alignX and alignY as the same time. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @param ax The align keyword or for instance "100px". E.g "left", "right", "leading" or "trailing". + * @param ay The align keyword or for instance "100px". E.g "top" or "bottom". + * @return <code>this</code> so it is possible to chain calls. E.g. <code>new LayoutConstraint().noGrid().gap().fill()</code>. + * @see #alignX(String) + * @see #alignY(String) + */ + public final LC align(String ax, String ay) + { + if (ax != null) + alignX(ax); + + if (ay != null) + alignY(ay); + + return this; + } + + /** Same functionality as <code>setGridGapX(ConstraintParser.parseBoundSize(boundsSize, true, true))</code> only this method + * returns <code>this</code> for chaining multiple calls. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @param boundsSize The <code>BoundSize</code> of the gap. This is a minimum and/or preferred and/or maximum size. E.g. + * <code>"50:100:200"</code> or <code>"100px"</code>. + * @return <code>this</code> so it is possible to chain calls. E.g. <code>new LayoutConstraint().noGrid().gap().fill()</code>. + * @see #setGridGapX(BoundSize) + */ + public final LC gridGapX(String boundsSize) + { + setGridGapX(ConstraintParser.parseBoundSize(boundsSize, true, true)); + return this; + } + + /** Same functionality as <code>setGridGapY(ConstraintParser.parseBoundSize(boundsSize, true, false))</code> only this method + * returns <code>this</code> for chaining multiple calls. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @param boundsSize The <code>BoundSize</code> of the gap. This is a minimum and/or preferred and/or maximum size. E.g. + * <code>"50:100:200"</code> or <code>"100px"</code>. + * @return <code>this</code> so it is possible to chain calls. E.g. <code>new LayoutConstraint().noGrid().gap().fill()</code>. + * @see #setGridGapY(BoundSize) + */ + public final LC gridGapY(String boundsSize) + { + setGridGapY(ConstraintParser.parseBoundSize(boundsSize, true, false)); + return this; + } + + /** Sets both grid gaps at the same time. see {@link #gridGapX(String)} and {@link #gridGapY(String)}. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @param gapx The <code>BoundSize</code> of the gap. This is a minimum and/or preferred and/or maximum size. E.g. + * <code>"50:100:200"</code> or <code>"100px"</code>. + * @param gapy The <code>BoundSize</code> of the gap. This is a minimum and/or preferred and/or maximum size. E.g. + * <code>"50:100:200"</code> or <code>"100px"</code>. + * @return <code>this</code> so it is possible to chain calls. E.g. <code>new LayoutConstraint().noGrid().gap().fill()</code>. + * @see #gridGapX(String) + * @see #gridGapY(String) + */ + public final LC gridGap(String gapx, String gapy) + { + if (gapx != null) + gridGapX(gapx); + + if (gapy != null) + gridGapY(gapy); + + return this; + } + + /** Same functionality as {@link #setDebugMillis(int repaintMillis)} only this method returns <code>this</code> for chaining multiple calls. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @param repaintMillis The new debug repaint interval. + * @return <code>this</code> so it is possible to chain calls. E.g. <code>new LayoutConstraint().noGrid().gap().fill()</code>. + * @see #setDebugMillis(int) + */ + public final LC debug(int repaintMillis) + { + setDebugMillis(repaintMillis); + return this; + } + + /** Same functionality as {@link #setHideMode(int mode)} only this method returns <code>this</code> for chaining multiple calls. + * <p> + * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com. + * @param mode The mode:<br> + * 0 == Normal. Bounds will be caclulated as if the component was visible.<br> + * 1 == If hidden the size will be 0, 0 but the gaps remain.<br> + * 2 == If hidden the size will be 0, 0 and gaps set to zero.<br> + * 3 == If hidden the component will be disregarded completely and not take up a cell in the grid.. + * @return <code>this</code> so it is possible to chain calls. E.g. <code>new LayoutConstraint().noGrid().gap().fill()</code>. + * @see #setHideMode(int) + */ + public final LC hideMode(int mode) + { + setHideMode(mode); + return this; + } + + // ************************************************ + // Persistence Delegate and Serializable combined. + // ************************************************ + + private Object readResolve() throws ObjectStreamException + { + return LayoutUtil.getSerializedObject(this); + } + + public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException + { + LayoutUtil.setSerializedObject(this, LayoutUtil.readAsXML(in)); + } + + public void writeExternal(ObjectOutput out) throws IOException + { + if (getClass() == LC.class) + LayoutUtil.writeAsXML(out, this); + } +} diff --git a/prototypes/miglayout/net/miginfocom/layout/LayoutCallback.java b/prototypes/miglayout/net/miginfocom/layout/LayoutCallback.java index f0855701..51acc218 100644 --- a/prototypes/miglayout/net/miginfocom/layout/LayoutCallback.java +++ b/prototypes/miglayout/net/miginfocom/layout/LayoutCallback.java @@ -1,48 +1,48 @@ -package net.miginfocom.layout;
-
-import net.miginfocom.layout.UnitValue;
-import net.miginfocom.layout.ComponentWrapper;
-import net.miginfocom.layout.BoundSize;
-
-/** A class to extend if you want to provide more control over where a component is placed or the size of it.
- * <p>
- * Note! Returned arrays from this class will never be altered. This means that caching of arrays in these methods
- * is OK.
- */
-public abstract class LayoutCallback
-{
- /** Returns a position similar to the "pos" the component constraint.
- * @param comp The component wrapper that holds the actual component (JComponent is Swing and Control in SWT).
- * <b>Should not be altered.</b>
- * @return The [x, y, x2, y2] as explained in the documentation for "pos". If <code>null</code>
- * is returned nothing is done and this is the default.
- * @see UnitValue
- * @see net.miginfocom.layout.ConstraintParser#parseUnitValue(String, boolean)
- */
- public UnitValue[] getPosition(ComponentWrapper comp)
- {
- return null;
- }
-
- /** Returns a size similar to the "width" and "height" in the component constraint.
- * @param comp The component wrapper that holds the actual component (JComponent is Swing and Control in SWT).
- * <b>Should not be altered.</b>
- * @return The [width, height] as explained in the documentation for "width" and "height". If <code>null</code>
- * is returned nothing is done and this is the default.
- * @see net.miginfocom.layout.BoundSize
- * @see net.miginfocom.layout.ConstraintParser#parseBoundSize(String, boolean, boolean)
- */
- public BoundSize[] getSize(ComponentWrapper comp)
- {
- return null;
- }
-
- /** A last minute change of the bounds. The bound for the layout cycle has been set and you can correct there
- * after any set of rules you like.
- * @param comp The component wrapper that holds the actual component (JComponent is Swing and Control in SWT).
- * <b>Should not be altered.</b>
- */
- public void correctBounds(ComponentWrapper comp)
- {
- }
-}
+package net.miginfocom.layout; + +import net.miginfocom.layout.UnitValue; +import net.miginfocom.layout.ComponentWrapper; +import net.miginfocom.layout.BoundSize; + +/** A class to extend if you want to provide more control over where a component is placed or the size of it. + * <p> + * Note! Returned arrays from this class will never be altered. This means that caching of arrays in these methods + * is OK. + */ +public abstract class LayoutCallback +{ + /** Returns a position similar to the "pos" the component constraint. + * @param comp The component wrapper that holds the actual component (JComponent is Swing and Control in SWT). + * <b>Should not be altered.</b> + * @return The [x, y, x2, y2] as explained in the documentation for "pos". If <code>null</code> + * is returned nothing is done and this is the default. + * @see UnitValue + * @see net.miginfocom.layout.ConstraintParser#parseUnitValue(String, boolean) + */ + public UnitValue[] getPosition(ComponentWrapper comp) + { + return null; + } + + /** Returns a size similar to the "width" and "height" in the component constraint. + * @param comp The component wrapper that holds the actual component (JComponent is Swing and Control in SWT). + * <b>Should not be altered.</b> + * @return The [width, height] as explained in the documentation for "width" and "height". If <code>null</code> + * is returned nothing is done and this is the default. + * @see net.miginfocom.layout.BoundSize + * @see net.miginfocom.layout.ConstraintParser#parseBoundSize(String, boolean, boolean) + */ + public BoundSize[] getSize(ComponentWrapper comp) + { + return null; + } + + /** A last minute change of the bounds. The bound for the layout cycle has been set and you can correct there + * after any set of rules you like. + * @param comp The component wrapper that holds the actual component (JComponent is Swing and Control in SWT). + * <b>Should not be altered.</b> + */ + public void correctBounds(ComponentWrapper comp) + { + } +} diff --git a/prototypes/miglayout/net/miginfocom/layout/LayoutUtil.java b/prototypes/miglayout/net/miginfocom/layout/LayoutUtil.java index 05d0633a..badee305 100644 --- a/prototypes/miglayout/net/miginfocom/layout/LayoutUtil.java +++ b/prototypes/miglayout/net/miginfocom/layout/LayoutUtil.java @@ -1,532 +1,532 @@ -package net.miginfocom.layout;
-
-import java.beans.*;
-import java.io.*;
-import java.util.IdentityHashMap;
-import java.util.TreeSet;
-import java.util.WeakHashMap;
-/*
- * License (BSD):
- * ==============
- *
- * Copyright (c) 2004, Mikael Grev, MiG InfoCom AB. (miglayout (at) miginfocom (dot) com)
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification,
- * are permitted provided that the following conditions are met:
- * Redistributions of source code must retain the above copyright notice, this list
- * of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above copyright notice, this
- * list of conditions and the following disclaimer in the documentation and/or other
- * materials provided with the distribution.
- * Neither the name of the MiG InfoCom AB nor the names of its contributors may be
- * used to endorse or promote products derived from this software without specific
- * prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
- * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
- * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
- * OF SUCH DAMAGE.
- *
- * @version 1.0
- * @author Mikael Grev, MiG InfoCom AB
- * Date: 2006-sep-08
- */
-
-/** A utility class that has only static helper methods.
- */
-public final class LayoutUtil
-{
- /** A substitute value for aa really large value. Integer.MAX_VALUE is not used since that means a lot of defensive code
- * for potential overflow must exist in many places. This value is large enough for being unresonable yet it is hard to
- * overflow.
- */
- static final int INF = (Integer.MAX_VALUE >> 10) - 100; // To reduce likelyhood of overflow errors when calculating.
-
- /** Tag int for a value that in considered "not set". Used as "null" element in int arays.
- */
- static final int NOT_SET = Integer.MIN_VALUE + 12346; // Magic value...
-
- // Index for the different sizes
- public static final int MIN = 0;
- public static final int PREF = 1;
- public static final int MAX = 2;
-
- private static WeakHashMap<Object, String> CR_MAP = null;
- private static WeakHashMap<Object, Boolean> DT_MAP = null; // The Containers that have design time. Value not used.
- private static int eSz = 15;
-
- private LayoutUtil()
- {
- }
-
- /** Returns the current version of MiG Layout.
- * @return The current version of MiG Layout.
- */
- public static String getVersion()
- {
- return "3.0.3";
- }
-
- /** Sets if design time is turned on for a Container in {@link ContainerWrapper}.
- * @param cw The container to set design time for. <code>null</code> is legal and can be used as
- * a key to turn on/off design time "in general". Note though that design time "in general" is
- * always on as long as there is at least one ContainerWrapper with design time.
- * <p>
- * <strong>If this method has not ever been called it will default to what
- * <code>Beans.isDesignTime()</code> returns.</strong> This means that if you call
- * this method you indicate that you will take responsibility for the design time value.
- * @param b <code>true</code> means design time on.
- */
- public static void setDesignTime(ContainerWrapper cw, boolean b)
- {
- if (DT_MAP == null)
- DT_MAP = new WeakHashMap<Object, Boolean>();
-
- DT_MAP.put((cw != null ? cw.getComponent() : null), new Boolean(b));
- }
-
- /** Returns if design time is turned on for a Container in {@link ContainerWrapper}.
- * @param cw The container to set design time for. <code>null</code> is legal will return <code>true</code>
- * if there is at least one <code>ContainerWrapper</code> (or <code>null</code>) that have design time
- * turned on.
- * @return If design time is set for <code>cw</code>.
- */
- public static boolean isDesignTime(ContainerWrapper cw)
- {
- if (DT_MAP == null)
- return Beans.isDesignTime();
-
- Boolean b = DT_MAP.get(cw != null ? cw.getComponent() : null);
- return b != null ? b.booleanValue() : false;
- }
-
- /** The size of an empty row or columns in a grid during design time.
- * @return The number of pixels. Default is 15.
- */
- public static int getDesignTimeEmptySize()
- {
- return eSz;
- }
-
- /** The size of an empty row or columns in a grid during design time.
- * @param pixels The number of pixels. Default is 15.
- */
- public static void setDesignTimeEmptySize(int pixels)
- {
- eSz = pixels;
- }
-
- /** Associates <code>con</code> with the creation string <code>s</code>. The <code>con</code> object should
- * probably have an equals method that compares identities or <code>con</code> objects that .equals() will only
- * be able to have <b>one</b> creation string.
- * <p>
- * If {@link LayoutUtil#isDesignTime(ContainerWrapper)} returns <code>false</code> the method does nothing.
- * @param con The object. if <code>null</code> the method does nothing.
- * @param s The creation string. if <code>null</code> the method does nothing.
- */
- static void putCCString(Object con, String s)
- {
- if (s != null && con != null && isDesignTime(null)) {
- if (CR_MAP == null)
- CR_MAP = new WeakHashMap<Object, String>(64);
-
- CR_MAP.put(con, s);
- }
- }
-
- /** Sets/add the persistence delagates to be used for a class.
- * @param c The class to set the registered deligate for.
- * @param del The new deligate or <code>null</code> to erase to old one.
- */
- static synchronized void setDelegate(Class c, PersistenceDelegate del)
- {
- try {
- Introspector.getBeanInfo(c).getBeanDescriptor().setValue("persistenceDelegate", del);
- } catch (Exception e1) {
- }
- }
-
- /** Returns strings set with {@link #putCCString(Object, String)} or <code>null</code> if nothing is associated or
- * {@link LayoutUtil#isDesignTime(ContainerWrapper)} returns <code>false</code>.
- * @param con The constraitn object.
- * @return The creation string or <code>null</code> if nothing is registered with the <code>con</code> object.
- */
- static String getCCString(Object con)
- {
- return CR_MAP != null ? CR_MAP.get(con) : null;
- }
-
- static void throwCC()
- {
- throw new IllegalStateException("setStoreConstraintData(true) must be set for strings to be saved.");
- }
-
- /** Takes a number on min/preferred/max sizes and resize constraints and returns the calculated sizes which sum should add up to <code>bounds</code>. Whether the sum
- * will actually equal <code>bounds</code> is dependent om the pref/max sizes and resise constraints.
- * @param sizes [ix],[MIN][PREF][MAX]. Grid.CompWrap.NOT_SET will be treated as N/A or 0. A "[MIN][PREF][MAX]" array with null elements will be interpreted as very flexible (no bounds)
- * but if the array itself is null it will not get any size.
- * @param resConstr Elements can be <code>null</code> and the whole array can be <code>null</code>. <code>null</code> means that the size will not be flexible at all.
- * Can have length less than <code>sizes</code> in which case the last element should be used for the elements missing.
- * @param defGrowWeights If there is no grow weight for a resConstr the correspinding value of this array is used.
- * These forced resConstr will be grown last though and only if needed to fill to the bounds.
- * @param startSizeType The initial size to use. E.g. {@link net.miginfocom.layout.LayoutUtil#MIN}.
- * @param bounds To use for relative sizes.
- * @return The sizes. Array length will match <code>sizes</code>.
- */
- static int[] calculateSerial(int[][] sizes, ResizeConstraint[] resConstr, Float[] defGrowWeights, int startSizeType, int bounds)
- {
- float[] lengths = new float[sizes.length]; // heights/widths that are set
- float usedLength = 0.0f;
-
- // Give all preferred size to start with
- for (int i = 0; i < sizes.length; i++) {
- if (sizes[i] != null) {
- float len = sizes[i][startSizeType] != NOT_SET ? sizes[i][startSizeType] : 0;
- int newSizeBounded = getBrokenBoundary(len, sizes[i][MIN], sizes[i][MAX]);
- if (newSizeBounded != NOT_SET)
- len = newSizeBounded;
-
- usedLength += len;
- lengths[i] = len;
- }
- }
-
- int useLengthI = Math.round(usedLength);
- if (useLengthI != bounds && resConstr != null) {
- boolean isGrow = useLengthI < bounds;
-
- // Create a Set with the available priorities
- TreeSet<Integer> prioList = new TreeSet<Integer>();
- for (int i = 0; i < sizes.length; i++) {
- ResizeConstraint resC = (ResizeConstraint) getIndexSafe(resConstr, i);
- if (resC != null)
- prioList.add(new Integer(isGrow ? resC.growPrio : resC.shrinkPrio));
- }
- Integer[] prioIntegers = prioList.toArray(new Integer[prioList.size()]);
-
- for (int force = 0; force <= ((isGrow && defGrowWeights != null) ? 1 : 0); force++) { // Run twice if defGrow and the need for growing.
- for (int pr = prioIntegers.length - 1; pr >= 0; pr--) {
- int curPrio = prioIntegers[pr].intValue();
-
- float totWeight = 0f;
- Float[] resizeWeight = new Float[sizes.length];
- for (int i = 0; i < sizes.length; i++) {
- if (sizes[i] == null) // if no min/pref/max size at all do not grow or shrink.
- continue;
-
- ResizeConstraint resC = (ResizeConstraint) getIndexSafe(resConstr, i);
- if (resC != null) {
- int prio = isGrow ? resC.growPrio : resC.shrinkPrio;
-
- if (curPrio == prio) {
- if (isGrow) {
- resizeWeight[i] = (force == 0 || resC.grow != null) ? resC.grow : (defGrowWeights[i < defGrowWeights.length ? i : defGrowWeights.length - 1]);
- } else {
- resizeWeight[i] = resC.shrink;
- }
- if (resizeWeight[i] != null)
- totWeight += resizeWeight[i].floatValue();
- }
- }
- }
-
- if (totWeight > 0f) {
- boolean hit;
- do {
- float toChange = bounds - usedLength;
- hit = false;
- float changedWeight = 0f;
- for (int i = 0; i < sizes.length && totWeight > 0.0001f; i++) {
-
- Float weight = resizeWeight[i];
- if (weight != null) {
- float sizeDelta = toChange * weight.floatValue() / totWeight;
- float newSize = lengths[i] + sizeDelta;
-
- if (sizes[i] != null) {
- int newSizeBounded = getBrokenBoundary(newSize, sizes[i][MIN], sizes[i][MAX]);
- if (newSizeBounded != NOT_SET) {
- resizeWeight[i] = null;
- hit = true;
- changedWeight += weight.floatValue();
- newSize = newSizeBounded;
- sizeDelta = newSize - lengths[i];
- }
- }
-
- lengths[i] = newSize;
- usedLength += sizeDelta;
- }
- }
- totWeight -= changedWeight;
- } while (hit);
- }
- }
- }
- }
- return roundSizes(lengths);
- }
-
- static Object getIndexSafe(Object[] arr, int ix)
- {
- return arr != null ? arr[ix < arr.length ? ix : arr.length - 1] : null;
- }
-
- /** Returns the broken boundary if <code>sz</code> is outside the boundaries <code>lower</code> or <code>upper</code>. If both boundaries
- * are broken, the lower one is returned. If <code>sz</code> is < 0 then <code>new Float(0f)</code> is returned so that no sizes can be
- * negative.
- * @param sz The size to check
- * @param lower The lower boundary (or <code>null</code> fo no boundary).
- * @param upper The upper boundary (or <code>null</code> fo no boundary).
- * @return The broken boundary or <code>null</code> if no boundary was broken.
- */
- private static int getBrokenBoundary(float sz, int lower, int upper)
- {
- if (lower != NOT_SET) {
- if (sz < lower)
- return new Integer(lower);
- } else if (sz < 0f) {
- return new Integer(0);
- }
-
- if (upper != NOT_SET && sz > upper)
- return new Integer(upper);
-
- return NOT_SET;
- }
-
-
- static int sum(int[] terms, int start, int len)
- {
- int s = 0;
- for (int i = start, iSz = start + len; i < iSz; i++)
- s += terms[i];
- return s;
- }
-
- static int sum(int[] terms)
- {
- return sum(terms, 0, terms.length);
- }
-
- public static int getSizeSafe(int[] sizes, int sizeType)
- {
- if (sizes == null || sizes[sizeType] == NOT_SET)
- return sizeType == MAX ? LayoutUtil.INF : 0;
- return sizes[sizeType];
- }
-
- static BoundSize derive(BoundSize bs, UnitValue min, UnitValue pref, UnitValue max)
- {
- if (bs == null)
- return new BoundSize(min, pref, max, null);
-
- return new BoundSize(
- min != null ? min : bs.getMin(),
- pref != null ? pref : bs.getPreferred(),
- max != null ? max : bs.getMax(), null);
- }
-
- /** Returns if left-to-right orientation is used. If not set explicitly in the layout constraints the Locale
- * of the <code>parent</code> is used.
- * @param lc The constraint if there is one. Can be <code>null</code>.
- * @param container The parent that may be used to get the left-to-right if ffc does not specify this.
- * @return If left-to-right orientation is currently used.
- */
- public final static boolean isLeftToRight(LC lc, ContainerWrapper container)
- {
- if (lc != null && lc.getLeftToRight() != null)
- return lc.getLeftToRight().booleanValue();
-
- return container == null || container.isLeftToRight();
- }
-
- /** Round a number of float sizes into int sizes so that the total length match up
- * @param sizes The sizes to round
- * @return An array of equal length as <code>sizes</code>.
- */
- static int[] roundSizes(float[] sizes)
- {
- int[] retInts = new int[sizes.length];
- float posD = 0;
-
- for (int i = 0; i < retInts.length; i++) {
- int posI = (int) (posD + 0.5f);
-
- posD += sizes[i];
-
- retInts[i] = (int) (posD + 0.5f) - posI;
- }
-
- return retInts;
- }
-
- /** Safe equals. null == null, but null never equals anything else.
- * @param o1 The first object. May be <code>null</code>.
- * @param o2 The second object. May be <code>null</code>.
- * @return Returns <code>true</code> if <code>o1</code> and <code>o2</code> are equal (using .equals()) or both are <code>null</code>.
- */
- static final boolean equals(Object o1, Object o2)
- {
- return o1 == o2 || (o1 != null && o2 != null && o1.equals(o2));
- }
-
-// static int getBaselineCorrect(Component comp)
-// {
-// Dimension pSize = comp.getPreferredSize();
-// int baseline = comp.getBaseline(pSize.width, pSize.height);
-// int nextBaseline = comp.getBaseline(pSize.width, pSize.height + 1);
-//
-// // Amount to add to height when calculating where baseline
-// // lands for a particular height:
-// int padding = 0;
-//
-// // Where the baseline is relative to the mid point
-// int baselineOffset = baseline - pSize.height / 2;
-// if (pSize.height % 2 == 0 && baseline != nextBaseline) {
-// padding = 1;
-// } else if (pSize.height % 2 == 1 && baseline == nextBaseline) {
-// baselineOffset--;
-// padding = 1;
-// }
-//
-// // The following calculates where the baseline lands for
-// // the height z:
-// return (pSize.height + padding) / 2 + baselineOffset;
-// }
-
- /** Converts a <code>float</code> to a string and is removing the ".0" if the float is an integer.
- * @param f the float.
- * @return <code>f</code> as a string. Never <code>null</code>.
- */
- static final String floatToString(float f)
- {
- String valS = String.valueOf(f);
- return valS.endsWith(".0") ? valS.substring(0, valS.length() - 2) : valS;
- }
-
- /** Returns the inset for the side.
- * @param side top == 0, left == 1, bottom = 2, right = 3.
- * @param getDefault If <code>true</code> the default insets will get retrieved if <code>lc</code> has none set.
- * @return The inset for the side. Never <code>null</code>.
- */
- static final UnitValue getInsets(LC lc, int side, boolean getDefault)
- {
- UnitValue[] i = lc.getInsets();
- return (i != null && i[side] != null) ? i[side] : (getDefault ? PlatformDefaults.getPanelInsets(side) : UnitValue.ZERO);
- }
-
- /** Writes the objet and CLOSES the stream. Uses the persistence delegate registered in this class.
- * @param os The stream to write to. Will be closed.
- * @param o The object to be serialized.
- * @param listener The listener to recieve the exeptions if there are any. If <code>null</code> not used.
- */
- static void writeXMLObject(OutputStream os, Object o, ExceptionListener listener)
- {
- ClassLoader oldClassLoader = Thread.currentThread().getContextClassLoader();
- Thread.currentThread().setContextClassLoader(LayoutUtil.class.getClassLoader());
-
- XMLEncoder encoder = new XMLEncoder(os);
-
- if (listener != null)
- encoder.setExceptionListener(listener);
-
- encoder.writeObject(o);
- encoder.close(); // Must be closed to write.
-
- Thread.currentThread().setContextClassLoader(oldClassLoader);
- }
-
- private static ByteArrayOutputStream writeOutputStream = null;
- /** Writes an object to XML.
- * @param out The boject out to write to. Will not be closed.
- * @param o The object to write.
- */
- public static synchronized void writeAsXML(ObjectOutput out, Object o) throws IOException
- {
- if (writeOutputStream == null)
- writeOutputStream = new ByteArrayOutputStream(16384);
-
- writeOutputStream.reset();
-
- writeXMLObject(writeOutputStream, o, new ExceptionListener() {
- public void exceptionThrown(Exception e) {
- e.printStackTrace();
- }});
-
- byte[] buf = writeOutputStream.toByteArray();
-
- out.writeInt(buf.length);
- out.write(buf);
- }
-
- private static byte[] readBuf = null;
- /** Reads an object from <code>in</code> using the
- * @param in The object input to read from.
- * @return The object. Never <code>null</code>.
- * @throws IOException If there was a problem saving as XML
- */
- public static synchronized Object readAsXML(ObjectInput in) throws IOException
- {
- if (readBuf == null)
- readBuf = new byte[16384];
-
- Thread cThread = Thread.currentThread();
- ClassLoader oldCL = null;
-
- try {
- oldCL = cThread.getContextClassLoader();
- cThread.setContextClassLoader(LayoutUtil.class.getClassLoader());
- } catch(SecurityException e) {
- }
-
- Object o = null;
- try {
- int length = in.readInt();
- if (length > readBuf.length)
- readBuf = new byte[length];
-
- in.readFully(readBuf, 0, length);
-
- o = new XMLDecoder(new ByteArrayInputStream(readBuf, 0, length)).readObject();
-
- } catch(EOFException e) {
- }
-
- if (oldCL != null)
- cThread.setContextClassLoader(oldCL);
-
- return o;
- }
-
- private static final IdentityHashMap<Object, Object> SER_MAP = new IdentityHashMap<Object, Object>(2);
-
- /** Sets the serialized object and associates it with <code>caller</code>.
- * @param caller The objec created <code>o</code>
- * @param o The just serialized object.
- */
- public static void setSerializedObject(Object caller, Object o)
- {
- synchronized(SER_MAP) {
- SER_MAP.put(caller, o);
- }
- }
-
- /** Returns the serialized object that are associated with <code>caller</code>. It also removes it from the list.
- * @param caller The original creator of the object.
- * @return The object.
- */
- public static Object getSerializedObject(Object caller)
- {
- synchronized(SER_MAP) {
- return SER_MAP.remove(caller);
- }
- }
-}
+package net.miginfocom.layout; + +import java.beans.*; +import java.io.*; +import java.util.IdentityHashMap; +import java.util.TreeSet; +import java.util.WeakHashMap; +/* + * License (BSD): + * ============== + * + * Copyright (c) 2004, Mikael Grev, MiG InfoCom AB. (miglayout (at) miginfocom (dot) com) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright notice, this list + * of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * Neither the name of the MiG InfoCom AB nor the names of its contributors may be + * used to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * @version 1.0 + * @author Mikael Grev, MiG InfoCom AB + * Date: 2006-sep-08 + */ + +/** A utility class that has only static helper methods. + */ +public final class LayoutUtil +{ + /** A substitute value for aa really large value. Integer.MAX_VALUE is not used since that means a lot of defensive code + * for potential overflow must exist in many places. This value is large enough for being unresonable yet it is hard to + * overflow. + */ + static final int INF = (Integer.MAX_VALUE >> 10) - 100; // To reduce likelyhood of overflow errors when calculating. + + /** Tag int for a value that in considered "not set". Used as "null" element in int arays. + */ + static final int NOT_SET = Integer.MIN_VALUE + 12346; // Magic value... + + // Index for the different sizes + public static final int MIN = 0; + public static final int PREF = 1; + public static final int MAX = 2; + + private static WeakHashMap<Object, String> CR_MAP = null; + private static WeakHashMap<Object, Boolean> DT_MAP = null; // The Containers that have design time. Value not used. + private static int eSz = 15; + + private LayoutUtil() + { + } + + /** Returns the current version of MiG Layout. + * @return The current version of MiG Layout. + */ + public static String getVersion() + { + return "3.0.3"; + } + + /** Sets if design time is turned on for a Container in {@link ContainerWrapper}. + * @param cw The container to set design time for. <code>null</code> is legal and can be used as + * a key to turn on/off design time "in general". Note though that design time "in general" is + * always on as long as there is at least one ContainerWrapper with design time. + * <p> + * <strong>If this method has not ever been called it will default to what + * <code>Beans.isDesignTime()</code> returns.</strong> This means that if you call + * this method you indicate that you will take responsibility for the design time value. + * @param b <code>true</code> means design time on. + */ + public static void setDesignTime(ContainerWrapper cw, boolean b) + { + if (DT_MAP == null) + DT_MAP = new WeakHashMap<Object, Boolean>(); + + DT_MAP.put((cw != null ? cw.getComponent() : null), new Boolean(b)); + } + + /** Returns if design time is turned on for a Container in {@link ContainerWrapper}. + * @param cw The container to set design time for. <code>null</code> is legal will return <code>true</code> + * if there is at least one <code>ContainerWrapper</code> (or <code>null</code>) that have design time + * turned on. + * @return If design time is set for <code>cw</code>. + */ + public static boolean isDesignTime(ContainerWrapper cw) + { + if (DT_MAP == null) + return Beans.isDesignTime(); + + Boolean b = DT_MAP.get(cw != null ? cw.getComponent() : null); + return b != null ? b.booleanValue() : false; + } + + /** The size of an empty row or columns in a grid during design time. + * @return The number of pixels. Default is 15. + */ + public static int getDesignTimeEmptySize() + { + return eSz; + } + + /** The size of an empty row or columns in a grid during design time. + * @param pixels The number of pixels. Default is 15. + */ + public static void setDesignTimeEmptySize(int pixels) + { + eSz = pixels; + } + + /** Associates <code>con</code> with the creation string <code>s</code>. The <code>con</code> object should + * probably have an equals method that compares identities or <code>con</code> objects that .equals() will only + * be able to have <b>one</b> creation string. + * <p> + * If {@link LayoutUtil#isDesignTime(ContainerWrapper)} returns <code>false</code> the method does nothing. + * @param con The object. if <code>null</code> the method does nothing. + * @param s The creation string. if <code>null</code> the method does nothing. + */ + static void putCCString(Object con, String s) + { + if (s != null && con != null && isDesignTime(null)) { + if (CR_MAP == null) + CR_MAP = new WeakHashMap<Object, String>(64); + + CR_MAP.put(con, s); + } + } + + /** Sets/add the persistence delagates to be used for a class. + * @param c The class to set the registered deligate for. + * @param del The new deligate or <code>null</code> to erase to old one. + */ + static synchronized void setDelegate(Class c, PersistenceDelegate del) + { + try { + Introspector.getBeanInfo(c).getBeanDescriptor().setValue("persistenceDelegate", del); + } catch (Exception e1) { + } + } + + /** Returns strings set with {@link #putCCString(Object, String)} or <code>null</code> if nothing is associated or + * {@link LayoutUtil#isDesignTime(ContainerWrapper)} returns <code>false</code>. + * @param con The constraitn object. + * @return The creation string or <code>null</code> if nothing is registered with the <code>con</code> object. + */ + static String getCCString(Object con) + { + return CR_MAP != null ? CR_MAP.get(con) : null; + } + + static void throwCC() + { + throw new IllegalStateException("setStoreConstraintData(true) must be set for strings to be saved."); + } + + /** Takes a number on min/preferred/max sizes and resize constraints and returns the calculated sizes which sum should add up to <code>bounds</code>. Whether the sum + * will actually equal <code>bounds</code> is dependent om the pref/max sizes and resise constraints. + * @param sizes [ix],[MIN][PREF][MAX]. Grid.CompWrap.NOT_SET will be treated as N/A or 0. A "[MIN][PREF][MAX]" array with null elements will be interpreted as very flexible (no bounds) + * but if the array itself is null it will not get any size. + * @param resConstr Elements can be <code>null</code> and the whole array can be <code>null</code>. <code>null</code> means that the size will not be flexible at all. + * Can have length less than <code>sizes</code> in which case the last element should be used for the elements missing. + * @param defGrowWeights If there is no grow weight for a resConstr the correspinding value of this array is used. + * These forced resConstr will be grown last though and only if needed to fill to the bounds. + * @param startSizeType The initial size to use. E.g. {@link net.miginfocom.layout.LayoutUtil#MIN}. + * @param bounds To use for relative sizes. + * @return The sizes. Array length will match <code>sizes</code>. + */ + static int[] calculateSerial(int[][] sizes, ResizeConstraint[] resConstr, Float[] defGrowWeights, int startSizeType, int bounds) + { + float[] lengths = new float[sizes.length]; // heights/widths that are set + float usedLength = 0.0f; + + // Give all preferred size to start with + for (int i = 0; i < sizes.length; i++) { + if (sizes[i] != null) { + float len = sizes[i][startSizeType] != NOT_SET ? sizes[i][startSizeType] : 0; + int newSizeBounded = getBrokenBoundary(len, sizes[i][MIN], sizes[i][MAX]); + if (newSizeBounded != NOT_SET) + len = newSizeBounded; + + usedLength += len; + lengths[i] = len; + } + } + + int useLengthI = Math.round(usedLength); + if (useLengthI != bounds && resConstr != null) { + boolean isGrow = useLengthI < bounds; + + // Create a Set with the available priorities + TreeSet<Integer> prioList = new TreeSet<Integer>(); + for (int i = 0; i < sizes.length; i++) { + ResizeConstraint resC = (ResizeConstraint) getIndexSafe(resConstr, i); + if (resC != null) + prioList.add(new Integer(isGrow ? resC.growPrio : resC.shrinkPrio)); + } + Integer[] prioIntegers = prioList.toArray(new Integer[prioList.size()]); + + for (int force = 0; force <= ((isGrow && defGrowWeights != null) ? 1 : 0); force++) { // Run twice if defGrow and the need for growing. + for (int pr = prioIntegers.length - 1; pr >= 0; pr--) { + int curPrio = prioIntegers[pr].intValue(); + + float totWeight = 0f; + Float[] resizeWeight = new Float[sizes.length]; + for (int i = 0; i < sizes.length; i++) { + if (sizes[i] == null) // if no min/pref/max size at all do not grow or shrink. + continue; + + ResizeConstraint resC = (ResizeConstraint) getIndexSafe(resConstr, i); + if (resC != null) { + int prio = isGrow ? resC.growPrio : resC.shrinkPrio; + + if (curPrio == prio) { + if (isGrow) { + resizeWeight[i] = (force == 0 || resC.grow != null) ? resC.grow : (defGrowWeights[i < defGrowWeights.length ? i : defGrowWeights.length - 1]); + } else { + resizeWeight[i] = resC.shrink; + } + if (resizeWeight[i] != null) + totWeight += resizeWeight[i].floatValue(); + } + } + } + + if (totWeight > 0f) { + boolean hit; + do { + float toChange = bounds - usedLength; + hit = false; + float changedWeight = 0f; + for (int i = 0; i < sizes.length && totWeight > 0.0001f; i++) { + + Float weight = resizeWeight[i]; + if (weight != null) { + float sizeDelta = toChange * weight.floatValue() / totWeight; + float newSize = lengths[i] + sizeDelta; + + if (sizes[i] != null) { + int newSizeBounded = getBrokenBoundary(newSize, sizes[i][MIN], sizes[i][MAX]); + if (newSizeBounded != NOT_SET) { + resizeWeight[i] = null; + hit = true; + changedWeight += weight.floatValue(); + newSize = newSizeBounded; + sizeDelta = newSize - lengths[i]; + } + } + + lengths[i] = newSize; + usedLength += sizeDelta; + } + } + totWeight -= changedWeight; + } while (hit); + } + } + } + } + return roundSizes(lengths); + } + + static Object getIndexSafe(Object[] arr, int ix) + { + return arr != null ? arr[ix < arr.length ? ix : arr.length - 1] : null; + } + + /** Returns the broken boundary if <code>sz</code> is outside the boundaries <code>lower</code> or <code>upper</code>. If both boundaries + * are broken, the lower one is returned. If <code>sz</code> is < 0 then <code>new Float(0f)</code> is returned so that no sizes can be + * negative. + * @param sz The size to check + * @param lower The lower boundary (or <code>null</code> fo no boundary). + * @param upper The upper boundary (or <code>null</code> fo no boundary). + * @return The broken boundary or <code>null</code> if no boundary was broken. + */ + private static int getBrokenBoundary(float sz, int lower, int upper) + { + if (lower != NOT_SET) { + if (sz < lower) + return new Integer(lower); + } else if (sz < 0f) { + return new Integer(0); + } + + if (upper != NOT_SET && sz > upper) + return new Integer(upper); + + return NOT_SET; + } + + + static int sum(int[] terms, int start, int len) + { + int s = 0; + for (int i = start, iSz = start + len; i < iSz; i++) + s += terms[i]; + return s; + } + + static int sum(int[] terms) + { + return sum(terms, 0, terms.length); + } + + public static int getSizeSafe(int[] sizes, int sizeType) + { + if (sizes == null || sizes[sizeType] == NOT_SET) + return sizeType == MAX ? LayoutUtil.INF : 0; + return sizes[sizeType]; + } + + static BoundSize derive(BoundSize bs, UnitValue min, UnitValue pref, UnitValue max) + { + if (bs == null) + return new BoundSize(min, pref, max, null); + + return new BoundSize( + min != null ? min : bs.getMin(), + pref != null ? pref : bs.getPreferred(), + max != null ? max : bs.getMax(), null); + } + + /** Returns if left-to-right orientation is used. If not set explicitly in the layout constraints the Locale + * of the <code>parent</code> is used. + * @param lc The constraint if there is one. Can be <code>null</code>. + * @param container The parent that may be used to get the left-to-right if ffc does not specify this. + * @return If left-to-right orientation is currently used. + */ + public final static boolean isLeftToRight(LC lc, ContainerWrapper container) + { + if (lc != null && lc.getLeftToRight() != null) + return lc.getLeftToRight().booleanValue(); + + return container == null || container.isLeftToRight(); + } + + /** Round a number of float sizes into int sizes so that the total length match up + * @param sizes The sizes to round + * @return An array of equal length as <code>sizes</code>. + */ + static int[] roundSizes(float[] sizes) + { + int[] retInts = new int[sizes.length]; + float posD = 0; + + for (int i = 0; i < retInts.length; i++) { + int posI = (int) (posD + 0.5f); + + posD += sizes[i]; + + retInts[i] = (int) (posD + 0.5f) - posI; + } + + return retInts; + } + + /** Safe equals. null == null, but null never equals anything else. + * @param o1 The first object. May be <code>null</code>. + * @param o2 The second object. May be <code>null</code>. + * @return Returns <code>true</code> if <code>o1</code> and <code>o2</code> are equal (using .equals()) or both are <code>null</code>. + */ + static final boolean equals(Object o1, Object o2) + { + return o1 == o2 || (o1 != null && o2 != null && o1.equals(o2)); + } + +// static int getBaselineCorrect(Component comp) +// { +// Dimension pSize = comp.getPreferredSize(); +// int baseline = comp.getBaseline(pSize.width, pSize.height); +// int nextBaseline = comp.getBaseline(pSize.width, pSize.height + 1); +// +// // Amount to add to height when calculating where baseline +// // lands for a particular height: +// int padding = 0; +// +// // Where the baseline is relative to the mid point +// int baselineOffset = baseline - pSize.height / 2; +// if (pSize.height % 2 == 0 && baseline != nextBaseline) { +// padding = 1; +// } else if (pSize.height % 2 == 1 && baseline == nextBaseline) { +// baselineOffset--; +// padding = 1; +// } +// +// // The following calculates where the baseline lands for +// // the height z: +// return (pSize.height + padding) / 2 + baselineOffset; +// } + + /** Converts a <code>float</code> to a string and is removing the ".0" if the float is an integer. + * @param f the float. + * @return <code>f</code> as a string. Never <code>null</code>. + */ + static final String floatToString(float f) + { + String valS = String.valueOf(f); + return valS.endsWith(".0") ? valS.substring(0, valS.length() - 2) : valS; + } + + /** Returns the inset for the side. + * @param side top == 0, left == 1, bottom = 2, right = 3. + * @param getDefault If <code>true</code> the default insets will get retrieved if <code>lc</code> has none set. + * @return The inset for the side. Never <code>null</code>. + */ + static final UnitValue getInsets(LC lc, int side, boolean getDefault) + { + UnitValue[] i = lc.getInsets(); + return (i != null && i[side] != null) ? i[side] : (getDefault ? PlatformDefaults.getPanelInsets(side) : UnitValue.ZERO); + } + + /** Writes the objet and CLOSES the stream. Uses the persistence delegate registered in this class. + * @param os The stream to write to. Will be closed. + * @param o The object to be serialized. + * @param listener The listener to recieve the exeptions if there are any. If <code>null</code> not used. + */ + static void writeXMLObject(OutputStream os, Object o, ExceptionListener listener) + { + ClassLoader oldClassLoader = Thread.currentThread().getContextClassLoader(); + Thread.currentThread().setContextClassLoader(LayoutUtil.class.getClassLoader()); + + XMLEncoder encoder = new XMLEncoder(os); + + if (listener != null) + encoder.setExceptionListener(listener); + + encoder.writeObject(o); + encoder.close(); // Must be closed to write. + + Thread.currentThread().setContextClassLoader(oldClassLoader); + } + + private static ByteArrayOutputStream writeOutputStream = null; + /** Writes an object to XML. + * @param out The boject out to write to. Will not be closed. + * @param o The object to write. + */ + public static synchronized void writeAsXML(ObjectOutput out, Object o) throws IOException + { + if (writeOutputStream == null) + writeOutputStream = new ByteArrayOutputStream(16384); + + writeOutputStream.reset(); + + writeXMLObject(writeOutputStream, o, new ExceptionListener() { + public void exceptionThrown(Exception e) { + e.printStackTrace(); + }}); + + byte[] buf = writeOutputStream.toByteArray(); + + out.writeInt(buf.length); + out.write(buf); + } + + private static byte[] readBuf = null; + /** Reads an object from <code>in</code> using the + * @param in The object input to read from. + * @return The object. Never <code>null</code>. + * @throws IOException If there was a problem saving as XML + */ + public static synchronized Object readAsXML(ObjectInput in) throws IOException + { + if (readBuf == null) + readBuf = new byte[16384]; + + Thread cThread = Thread.currentThread(); + ClassLoader oldCL = null; + + try { + oldCL = cThread.getContextClassLoader(); + cThread.setContextClassLoader(LayoutUtil.class.getClassLoader()); + } catch(SecurityException e) { + } + + Object o = null; + try { + int length = in.readInt(); + if (length > readBuf.length) + readBuf = new byte[length]; + + in.readFully(readBuf, 0, length); + + o = new XMLDecoder(new ByteArrayInputStream(readBuf, 0, length)).readObject(); + + } catch(EOFException e) { + } + + if (oldCL != null) + cThread.setContextClassLoader(oldCL); + + return o; + } + + private static final IdentityHashMap<Object, Object> SER_MAP = new IdentityHashMap<Object, Object>(2); + + /** Sets the serialized object and associates it with <code>caller</code>. + * @param caller The objec created <code>o</code> + * @param o The just serialized object. + */ + public static void setSerializedObject(Object caller, Object o) + { + synchronized(SER_MAP) { + SER_MAP.put(caller, o); + } + } + + /** Returns the serialized object that are associated with <code>caller</code>. It also removes it from the list. + * @param caller The original creator of the object. + * @return The object. + */ + public static Object getSerializedObject(Object caller) + { + synchronized(SER_MAP) { + return SER_MAP.remove(caller); + } + } +} diff --git a/prototypes/miglayout/net/miginfocom/layout/LinkHandler.java b/prototypes/miglayout/net/miginfocom/layout/LinkHandler.java index 8984bea1..96df386d 100644 --- a/prototypes/miglayout/net/miginfocom/layout/LinkHandler.java +++ b/prototypes/miglayout/net/miginfocom/layout/LinkHandler.java @@ -1,182 +1,182 @@ -package net.miginfocom.layout;
-
-import java.lang.ref.WeakReference;
-import java.util.ArrayList;
-import java.util.HashMap;
-/*
- * License (BSD):
- * ==============
- *
- * Copyright (c) 2004, Mikael Grev, MiG InfoCom AB. (miglayout (at) miginfocom (dot) com)
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification,
- * are permitted provided that the following conditions are met:
- * Redistributions of source code must retain the above copyright notice, this list
- * of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above copyright notice, this
- * list of conditions and the following disclaimer in the documentation and/or other
- * materials provided with the distribution.
- * Neither the name of the MiG InfoCom AB nor the names of its contributors may be
- * used to endorse or promote products derived from this software without specific
- * prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
- * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
- * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
- * OF SUCH DAMAGE.
- *
- * @version 1.0
- * @author Mikael Grev, MiG InfoCom AB
- * Date: 2006-sep-08
- */
-
-/**
- */
-public final class LinkHandler
-{
- public static final int X = 0;
- public static final int Y = 1;
- public static final int WIDTH = 2;
- public static final int HEIGHT = 3;
- public static final int X2 = 4;
- public static final int Y2 = 5;
-
- private static final ArrayList<WeakReference<Object>> LAYOUTS = new ArrayList<WeakReference<Object>>(4);
- private static final ArrayList<HashMap<String, int[]>> VALUES = new ArrayList<HashMap<String, int[]>>(4);
- private static final ArrayList<HashMap<String, int[]>> VALUES_TEMP = new ArrayList<HashMap<String, int[]>>(4);
-
- private LinkHandler()
- {
- }
-
- public synchronized static Integer getValue(Object layout, String key, int type)
- {
- Integer ret = null;
- boolean cont = true;
-
- for (int i = LAYOUTS.size() - 1; i >= 0; i--) {
- Object l = LAYOUTS.get(i).get();
- if (ret == null && l == layout) {
- int[] rect = VALUES_TEMP.get(i).get(key);
- if (cont && rect != null && rect[type] != LayoutUtil.NOT_SET) {
- ret = new Integer(rect[type]);
- } else {
- rect = VALUES.get(i).get(key);
- ret = (rect != null && rect[type] != LayoutUtil.NOT_SET) ? new Integer(rect[type]) : null;
- }
- cont = false;
- }
-
- if (l == null) {
- LAYOUTS.remove(i);
- VALUES.remove(i);
- VALUES_TEMP.remove(i);
- }
- }
- return ret;
- }
-
- public synchronized static boolean setBounds(Object layout, String key, int x, int y, int width, int height)
- {
- return setBounds(layout, key, x, y, width, height, false, false);
- }
-
- synchronized static boolean setBounds(Object layout, String key, int x, int y, int width, int height, boolean temporary, boolean incCur)
- {
- for (int i = LAYOUTS.size() - 1; i >= 0; i--) {
- Object l = LAYOUTS.get(i).get();
- if (l == layout) {
- HashMap<String, int[]> map = (temporary ? VALUES_TEMP : VALUES).get(i);
- int[] old = map.get(key);
-
- if (old == null || old[X] != x || old[Y] != y || old[WIDTH] != width || old[HEIGHT] != height) {
- if (old == null || incCur == false) {
- map.put(key, new int[] {x, y, width, height, x + width, y + height});
- return true;
- } else {
- boolean changed = false;
-
- if (x != LayoutUtil.NOT_SET) {
- if (old[X] == LayoutUtil.NOT_SET || x < old[X]) {
- old[X] = x;
- old[WIDTH] = old[X2] - x;
- changed = true;
- }
-
- if (width != LayoutUtil.NOT_SET) {
- int x2 = x + width;
- if (old[X2] == LayoutUtil.NOT_SET || x2 > old[X2]) {
- old[X2] = x2;
- old[WIDTH] = x2 - old[X];
- changed = true;
- }
- }
- }
-
- if (y != LayoutUtil.NOT_SET) {
- if (old[Y] == LayoutUtil.NOT_SET || y < old[Y]) {
- old[Y] = y;
- old[HEIGHT] = old[Y2] - y;
- changed = true;
- }
-
- if (height != LayoutUtil.NOT_SET) {
- int y2 = y + height;
- if (old[Y2] == LayoutUtil.NOT_SET || y2 > old[Y2]) {
- old[Y2] = y2;
- old[HEIGHT] = y2 - old[Y];
- changed = true;
- }
- }
- }
- return changed;
- }
- }
- return false;
- }
- }
-
- LAYOUTS.add(new WeakReference<Object>(layout));
- int[] bounds = new int[] {x, y, width, height, x + width, y + height};
-
- HashMap<String, int[]> values = new HashMap<String, int[]>(4);
- if (temporary)
- values.put(key, bounds);
- VALUES_TEMP.add(values);
-
- values = new HashMap<String, int[]>(4);
- if (temporary == false)
- values.put(key, bounds);
- VALUES.add(values);
-
- return true;
- }
-
- public synchronized static boolean clearBounds(Object layout, String key)
- {
- for (int i = LAYOUTS.size() - 1; i >= 0; i--) {
- Object l = LAYOUTS.get(i).get();
- if (l == layout)
- return VALUES.get(i).remove(key) != null;
- }
- return false;
- }
-
- synchronized static void clearTemporaryBounds(Object layout)
- {
- for (int i = LAYOUTS.size() - 1; i >= 0; i--) {
- Object l = LAYOUTS.get(i).get();
- if (l == layout) {
- VALUES_TEMP.get(i).clear();
- return;
- }
- }
- }
-}
+package net.miginfocom.layout; + +import java.lang.ref.WeakReference; +import java.util.ArrayList; +import java.util.HashMap; +/* + * License (BSD): + * ============== + * + * Copyright (c) 2004, Mikael Grev, MiG InfoCom AB. (miglayout (at) miginfocom (dot) com) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright notice, this list + * of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * Neither the name of the MiG InfoCom AB nor the names of its contributors may be + * used to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * @version 1.0 + * @author Mikael Grev, MiG InfoCom AB + * Date: 2006-sep-08 + */ + +/** + */ +public final class LinkHandler +{ + public static final int X = 0; + public static final int Y = 1; + public static final int WIDTH = 2; + public static final int HEIGHT = 3; + public static final int X2 = 4; + public static final int Y2 = 5; + + private static final ArrayList<WeakReference<Object>> LAYOUTS = new ArrayList<WeakReference<Object>>(4); + private static final ArrayList<HashMap<String, int[]>> VALUES = new ArrayList<HashMap<String, int[]>>(4); + private static final ArrayList<HashMap<String, int[]>> VALUES_TEMP = new ArrayList<HashMap<String, int[]>>(4); + + private LinkHandler() + { + } + + public synchronized static Integer getValue(Object layout, String key, int type) + { + Integer ret = null; + boolean cont = true; + + for (int i = LAYOUTS.size() - 1; i >= 0; i--) { + Object l = LAYOUTS.get(i).get(); + if (ret == null && l == layout) { + int[] rect = VALUES_TEMP.get(i).get(key); + if (cont && rect != null && rect[type] != LayoutUtil.NOT_SET) { + ret = new Integer(rect[type]); + } else { + rect = VALUES.get(i).get(key); + ret = (rect != null && rect[type] != LayoutUtil.NOT_SET) ? new Integer(rect[type]) : null; + } + cont = false; + } + + if (l == null) { + LAYOUTS.remove(i); + VALUES.remove(i); + VALUES_TEMP.remove(i); + } + } + return ret; + } + + public synchronized static boolean setBounds(Object layout, String key, int x, int y, int width, int height) + { + return setBounds(layout, key, x, y, width, height, false, false); + } + + synchronized static boolean setBounds(Object layout, String key, int x, int y, int width, int height, boolean temporary, boolean incCur) + { + for (int i = LAYOUTS.size() - 1; i >= 0; i--) { + Object l = LAYOUTS.get(i).get(); + if (l == layout) { + HashMap<String, int[]> map = (temporary ? VALUES_TEMP : VALUES).get(i); + int[] old = map.get(key); + + if (old == null || old[X] != x || old[Y] != y || old[WIDTH] != width || old[HEIGHT] != height) { + if (old == null || incCur == false) { + map.put(key, new int[] {x, y, width, height, x + width, y + height}); + return true; + } else { + boolean changed = false; + + if (x != LayoutUtil.NOT_SET) { + if (old[X] == LayoutUtil.NOT_SET || x < old[X]) { + old[X] = x; + old[WIDTH] = old[X2] - x; + changed = true; + } + + if (width != LayoutUtil.NOT_SET) { + int x2 = x + width; + if (old[X2] == LayoutUtil.NOT_SET || x2 > old[X2]) { + old[X2] = x2; + old[WIDTH] = x2 - old[X]; + changed = true; + } + } + } + + if (y != LayoutUtil.NOT_SET) { + if (old[Y] == LayoutUtil.NOT_SET || y < old[Y]) { + old[Y] = y; + old[HEIGHT] = old[Y2] - y; + changed = true; + } + + if (height != LayoutUtil.NOT_SET) { + int y2 = y + height; + if (old[Y2] == LayoutUtil.NOT_SET || y2 > old[Y2]) { + old[Y2] = y2; + old[HEIGHT] = y2 - old[Y]; + changed = true; + } + } + } + return changed; + } + } + return false; + } + } + + LAYOUTS.add(new WeakReference<Object>(layout)); + int[] bounds = new int[] {x, y, width, height, x + width, y + height}; + + HashMap<String, int[]> values = new HashMap<String, int[]>(4); + if (temporary) + values.put(key, bounds); + VALUES_TEMP.add(values); + + values = new HashMap<String, int[]>(4); + if (temporary == false) + values.put(key, bounds); + VALUES.add(values); + + return true; + } + + public synchronized static boolean clearBounds(Object layout, String key) + { + for (int i = LAYOUTS.size() - 1; i >= 0; i--) { + Object l = LAYOUTS.get(i).get(); + if (l == layout) + return VALUES.get(i).remove(key) != null; + } + return false; + } + + synchronized static void clearTemporaryBounds(Object layout) + { + for (int i = LAYOUTS.size() - 1; i >= 0; i--) { + Object l = LAYOUTS.get(i).get(); + if (l == layout) { + VALUES_TEMP.get(i).clear(); + return; + } + } + } +} diff --git a/prototypes/miglayout/net/miginfocom/layout/PlatformDefaults.java b/prototypes/miglayout/net/miginfocom/layout/PlatformDefaults.java index d805812a..52a34f72 100644 --- a/prototypes/miglayout/net/miginfocom/layout/PlatformDefaults.java +++ b/prototypes/miglayout/net/miginfocom/layout/PlatformDefaults.java @@ -1,675 +1,675 @@ -package net.miginfocom.layout;
-
-import javax.swing.*;
-import java.util.HashMap;
-/*
- * License (BSD):
- * ==============
- *
- * Copyright (c) 2004, Mikael Grev, MiG InfoCom AB. (miglayout (at) miginfocom (dot) com)
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification,
- * are permitted provided that the following conditions are met:
- * Redistributions of source code must retain the above copyright notice, this list
- * of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above copyright notice, this
- * list of conditions and the following disclaimer in the documentation and/or other
- * materials provided with the distribution.
- * Neither the name of the MiG InfoCom AB nor the names of its contributors may be
- * used to endorse or promote products derived from this software without specific
- * prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
- * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
- * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
- * OF SUCH DAMAGE.
- *
- * @version 1.0
- * @author Mikael Grev, MiG InfoCom AB
- * Date: 2006-sep-08
- */
-
-/** Currently handles Windows and Mac OS X spacing.
- */
-public final class PlatformDefaults
-{
- private static int DEF_H_UNIT = UnitValue.LPX;
- private static int DEF_V_UNIT = UnitValue.LPY;
-
- private static InCellGapProvider GAP_PROVIDER = null;
-
- private static volatile int MOD_COUNT = 0;
-
- private static final UnitValue LPX4 = new UnitValue(4, UnitValue.LPX, null);
- private static final UnitValue LPX7 = new UnitValue(7, UnitValue.LPX, null);
- private static final UnitValue LPX8 = new UnitValue(8, UnitValue.LPX, null);
- private static final UnitValue LPX9 = new UnitValue(9, UnitValue.LPX, null);
- private static final UnitValue LPX10 = new UnitValue(10, UnitValue.LPX, null);
- private static final UnitValue LPX11 = new UnitValue(11, UnitValue.LPX, null);
- private static final UnitValue LPX12 = new UnitValue(12, UnitValue.LPX, null);
- private static final UnitValue LPX14 = new UnitValue(14, UnitValue.LPX, null);
- private static final UnitValue LPX16 = new UnitValue(16, UnitValue.LPX, null);
- private static final UnitValue LPX20 = new UnitValue(20, UnitValue.LPX, null);
-
- private static final UnitValue LPY4 = new UnitValue(4, UnitValue.LPY, null);
- private static final UnitValue LPY7 = new UnitValue(7, UnitValue.LPY, null);
- private static final UnitValue LPY8 = new UnitValue(8, UnitValue.LPY, null);
- private static final UnitValue LPY9 = new UnitValue(9, UnitValue.LPY, null);
- private static final UnitValue LPY10 = new UnitValue(10, UnitValue.LPY, null);
- private static final UnitValue LPY11 = new UnitValue(11, UnitValue.LPY, null);
- private static final UnitValue LPY12 = new UnitValue(12, UnitValue.LPY, null);
- private static final UnitValue LPY14 = new UnitValue(14, UnitValue.LPY, null);
- private static final UnitValue LPY16 = new UnitValue(16, UnitValue.LPY, null);
- private static final UnitValue LPY20 = new UnitValue(20, UnitValue.LPY, null);
-
- public static final int WINDOWS_XP = 0;
- public static final int MAC_OSX = 1;
-// private static final int GNOME = 2;
-// private static final int KDE = 3;
-
- private static int CUR_PLAF = WINDOWS_XP;
-
- // Used for holding values.
- private final static UnitValue[] PANEL_INS = new UnitValue[4];
- private final static UnitValue[] DIALOG_INS = new UnitValue[4];
-
- private static String BUTTON_FORMAT = null;
-
- private static final HashMap<String, UnitValue> HOR_DEFS = new HashMap<String, UnitValue>(32);
- private static final HashMap<String, UnitValue> VER_DEFS = new HashMap<String, UnitValue>(32);
- private static BoundSize DEF_VGAP = null, DEF_HGAP = null;
- static BoundSize RELATED_X = null, RELATED_Y = null, UNRELATED_X = null, UNRELATED_Y = null;
- private static UnitValue BUTT_WIDTH = null;
-
- private static Float horScale = null, verScale = null;
-
- /** I value indicating that the size of the font for the container of the component
- * will be used as a base for calculating the logical pixel size. This is much as how
- * Windows calculated DLU (dialog units).
- * @see net.miginfocom.layout.UnitValue#LPX
- * @see net.miginfocom.layout.UnitValue#LPY
- * @see #setLogicalPixelBase(int)
- */
- public static final int BASE_FONT_SIZE = 100;
-
- /** I value indicating that the screen DPI will be used as a base for calculating the
- * logical pixel size.
- * <p>
- * This is the default value.
- * @see net.miginfocom.layout.UnitValue#LPX
- * @see net.miginfocom.layout.UnitValue#LPY
- * @see #setLogicalPixelBase(int)
- * @see #setVerticalScaleFactor(Float)
- * @see #setHorizontalScaleFactor(Float)
- */
- public static final int BASE_SCALE_FACTOR = 101;
-
- /** I value indicating that the size of a logica pixel should always be a real pixel
- * and thus no compensation will be made.
- * @see net.miginfocom.layout.UnitValue#LPX
- * @see net.miginfocom.layout.UnitValue#LPY
- * @see #setLogicalPixelBase(int)
- */
- public static final int BASE_REAL_PIXEL = 102;
-
- private static int LP_BASE = BASE_SCALE_FACTOR;
-
- private static int BASE_DPI = 96;
-
- static {
- setPlatform(getCurrentPlatform());
- MOD_COUNT = 0;
- }
-
- /** Returns the platform that the JRE is running on currently.
- * @return The platform that the JRE is running on currently. E.g. {@link #MAC_OSX} or {@link #WINDOWS_XP}.
- */
- public static int getCurrentPlatform()
- {
- return System.getProperty("os.name").startsWith("Mac OS") ? MAC_OSX : WINDOWS_XP;
- }
-
- private PlatformDefaults()
- {
- }
-
- /** Set the defaults to the default for the platform
- * @param plaf The platform. <code>PlatformDefaults.WINDOWS</code> or <code>PlatformDefaults.MAC_OSX</code>
- */
- public static void setPlatform(int plaf)
- {
- if (plaf < WINDOWS_XP || plaf > MAC_OSX)
- throw new IllegalArgumentException("Unknown platform: " + plaf);
-
- CUR_PLAF = plaf;
- if (plaf == WINDOWS_XP) {
- setRelatedGap(LPX4, LPY4);
- setUnrelatedGap(LPX7, LPY9);
- setParagraphGap(LPX14, LPY14);
- setIndentGap(LPX9, LPY9);
- setGridCellGap(LPX4, LPY4);
-
- setMinimumButtonWidth(new UnitValue(75, UnitValue.LPX, null));
- setButtonOrder("L_E+U+YNBXOCAH_R");
- setDialogInsets(LPY11, LPX11, LPY11, LPX11);
- setPanelInsets(LPY7, LPX7, LPY7, LPX7);
- BASE_DPI = 96;
- } else {
- setRelatedGap(LPX8, LPY8);
- setUnrelatedGap(LPX12, LPY12);
- setParagraphGap(LPX16, LPY16);
- setIndentGap(LPX10, LPY10);
- setGridCellGap(LPX8, LPY8);
-
- setMinimumButtonWidth(new UnitValue(68, UnitValue.LPX, null));
- setButtonOrder("L_HE+U+NYBXCOA_R");
- setDialogInsets(LPY14, LPX20, LPY20, LPX20);
- setPanelInsets(LPY16, LPX16, LPY16, LPX16);
- BASE_DPI = 72;
- }
- }
-
- /** Returns the current platform
- * @return <code>PlatformDefaults.WINDOWS</code> or <code>PlatformDefaults.MAC_OSX</code>
- */
- public static int getPlatform()
- {
- return CUR_PLAF;
- }
-
- public static int getDefaultDPI()
- {
- return BASE_DPI;
- }
-
- /** The forced scale factor that all screen relative units (e.g. millimeters, inches and logical pixels) will be multiplied
- * with. If <code>null</code> this will default to a scale that will scale the current screen to the default screen resolution
- * (72 DPI for Mac and 92 DPI for Windows).
- * @return The forced scale or <code>null</code> for default scaling.
- * @see #getHorizontalScaleFactor()
- * @see ComponentWrapper#getHorizontalScreenDPI()
- */
- public static Float
- getHorizontalScaleFactor()
- {
- return horScale;
- }
-
- /** The forced scale factor that all screen relative units (e.g. millimeters, inches and logical pixels) will be multiplied
- * with. If <code>null</code> this will default to a scale that will scale the current screen to the default screen resolution
- * (72 DPI for Mac and 92 DPI for Windows).
- * @param f The forced scale or <code>null</code> for default scaling.
- * @see #getHorizontalScaleFactor()
- * @see ComponentWrapper#getHorizontalScreenDPI()
- */
- public static void setHorizontalScaleFactor(Float f)
- {
- if (horScale != f) {
- horScale = f;
- MOD_COUNT++;
- }
- }
-
- /** The forced scale factor that all screen relative units (e.g. millimeters, inches and logical pixels) will be multiplied
- * with. If <code>null</code> this will default to a scale that will scale the current screen to the default screen resolution
- * (72 DPI for Mac and 92 DPI for Windows).
- * @return The forced scale or <code>null</code> for default scaling.
- * @see #getHorizontalScaleFactor()
- * @see ComponentWrapper#getVerticalScreenDPI()
- */
- public static Float getVerticalScaleFactor()
- {
- return verScale;
- }
-
- /** The forced scale factor that all screen relative units (e.g. millimeters, inches and logical pixels) will be multiplied
- * with. If <code>null</code> this will default to a scale that will scale the current screen to the default screen resolution
- * (72 DPI for Mac and 92 DPI for Windows).
- * @param f The forced scale or <code>null</code> for default scaling.
- * @see #getHorizontalScaleFactor()
- * @see ComponentWrapper#getVerticalScreenDPI()
- */
- public static void setVerticalScaleFactor(Float f)
- {
- if (verScale != f) {
- verScale = f;
- MOD_COUNT++;
- }
- }
-
- /** What base value should be used to calculate logical pixel sizes.
- * @return The current base. Default is {@link #BASE_SCALE_FACTOR}
- * @see #BASE_FONT_SIZE
- * @see # BASE_SCREEN_DPI_FACTOR
- * @see #BASE_REAL_PIXEL
- */
- public static int getLogicalPixelBase()
- {
- return LP_BASE;
- }
-
- /** What base value should be used to calculate logical pixel sizes.
- * @param base The new base. Default is {@link #BASE_SCALE_FACTOR}
- * @see #BASE_FONT_SIZE
- * @see # BASE_SCREEN_DPI_FACTOR
- * @see #BASE_REAL_PIXEL
- */
- public static void setLogicalPixelBase(int base)
- {
- if (LP_BASE != base) {
- if (base < BASE_FONT_SIZE || base > BASE_SCALE_FACTOR)
- throw new IllegalArgumentException("Unrecognized base: " + base);
-
- LP_BASE = base;
- MOD_COUNT++;
- }
- }
-
- /** Sets gap value for components that are "related".
- * @param x The value that will be transformed to pixels. If <code>null</code> the current value will not change.
- * @param y The value that will be transformed to pixels. If <code>null</code> the current value will not change.
- */
- public static void setRelatedGap(UnitValue x, UnitValue y)
- {
- setUnitValue(new String[] {"r", "rel", "related"}, x, y);
-
- RELATED_X = new BoundSize(x, x, null, "rel:rel");
- RELATED_Y = new BoundSize(y, y, null, "rel:rel");
- }
-
- /** Sets gap value for components that are "unrelated".
- * @param x The value that will be transformed to pixels. If <code>null</code> the current value will not change.
- * @param y The value that will be transformed to pixels. If <code>null</code> the current value will not change.
- */
- public static void setUnrelatedGap(UnitValue x, UnitValue y)
- {
- setUnitValue(new String[] {"u", "unrel", "unrelated"}, x, y);
-
- UNRELATED_X = new BoundSize(x, x, null, "unrel:unrel");
- UNRELATED_Y = new BoundSize(y, y, null, "unrel:unrel");
- }
-
- /** Sets paragraph gap value for components.
- * @param x The value that will be transformed to pixels. If <code>null</code> the current value will not change.
- * @param y The value that will be transformed to pixels. If <code>null</code> the current value will not change.
- */
- public static void setParagraphGap(UnitValue x, UnitValue y)
- {
- setUnitValue(new String[] {"p", "para", "paragraph"}, x, y);
- }
-
- /** Sets gap value for components that are "intended".
- * @param x The value that will be transformed to pixels. If <code>null</code> the current value will not change.
- * @param y The value that will be transformed to pixels. If <code>null</code> the current value will not change.
- */
- public static void setIndentGap(UnitValue x, UnitValue y)
- {
- setUnitValue(new String[] {"i", "ind", "indent"}, x, y);
- }
-
- /** Sets gap between two cells in the grid. Note that this is not a gap between component IN a cell, that has to be set
- * on the component constraints. The value will be the min and preferred size of the gap.
- * @param x The value that will be transformed to pixels. If <code>null</code> the current value will not change.
- * @param y The value that will be transformed to pixels. If <code>null</code> the current value will not change.
- */
- public static void setGridCellGap(UnitValue x, UnitValue y)
- {
- if (x != null)
- DEF_HGAP = new BoundSize(x, x, null, null);
-
- if (y != null)
- DEF_VGAP = new BoundSize(y, y, null, null);
-
- MOD_COUNT++;
- }
-
- /** Sets the recommended minimum button width.
- * @param width The recommended minimum button width.
- */
- public static void setMinimumButtonWidth(UnitValue width)
- {
- BUTT_WIDTH = width;
- MOD_COUNT++;
- }
-
- /** Returns the recommended minimum button width depending on the current set platform.
- * @return The recommended minimum button width depending on the current set platform.
- */
- public static UnitValue getMinimumButtonWidth()
- {
- return BUTT_WIDTH;
- }
-
- /** Returns the unit value associated with the unit. (E.i. "related" or "indent"). Must be lower case.
- * @param unit The unit string.
- * @return Tthe unit value associated with the unit. <code>null</code> for unrecognized units.
- */
- public static UnitValue getUnitValueX(String unit)
- {
- return HOR_DEFS.get(unit);
- }
-
- /** Returns the unit value associated with the unit. (E.i. "related" or "indent"). Must be lower case.
- * @param unit The unit string.
- * @return Tthe unit value associated with the unit. <code>null</code> for unrecognized units.
- */
- public static UnitValue getUnitValueY(String unit)
- {
- return VER_DEFS.get(unit);
- }
-
- /** Sets the unit value assiciated with a unit string. This may be used to store values for new unit strings
- * or modify old. Note that if a built in unit (such as "related") is modified all versions of it must be
- * set (I.e. "r", "rel" and "related"). The build in values will be reset to the default ones if the platform
- * is re-set.
- * @param unitStrings The unit strings. E.g. "mu", "myunit". Will be converted to lower case and trimmed. Not <code>null</code>.
- * @param x The value for the horizontal dimension. If <code>null</code> the value is not changed.
- * @param y The value for the vertical dimension. Might be same object as for <code>x</code>. If <code>null</code> the value is not changed.
- */
- public static final void setUnitValue(String[] unitStrings, UnitValue x, UnitValue y)
- {
- for (int i = 0; i < unitStrings.length; i++) {
- String s = unitStrings[i].toLowerCase().trim();
- if (x != null)
- HOR_DEFS.put(s, x);
- if (y != null)
- VER_DEFS.put(s, y);
- }
- MOD_COUNT++;
- }
-
- /** Understands ("r", "rel", "related") OR ("u", "unrel", "unrelated") OR ("i", "ind", "indent") OR ("p", "para", "paragraph").
- */
- static final int convertToPixels(float value, String unit, boolean isHor, float ref, ContainerWrapper parent, ComponentWrapper comp)
- {
- UnitValue uv = (isHor ? HOR_DEFS : VER_DEFS).get(unit);
- return uv != null ? Math.round(value * uv.getPixels(ref, parent, comp)) : UnitConverter.UNABLE;
- }
-
- /** Returns the order for the typical buttons in a standard button bar. It is one letter per button type.
- * @return The button order.
- * @see #setButtonOrder(String)
- */
- public static final String getButtonOrder()
- {
- return BUTTON_FORMAT;
- }
-
- /** Sets the order for the typical buttons in a standard button bar. It is one letter per button type.
- * <p>
- * Letter in upper case will get the minimum button width that the {@link #getMinimumButtonWidth()} specifies
- * and letters in lower case will get the width the corrent look&feel specifies.
- * <p>
- * Gaps will never be added to before the first component or after the last component. However, '+' (push) will be
- * applied before and after as well, but with a minimum size of 0 if first/last so there will not be a gap
- * before or after.
- * <p>
- * If gaps are explicitly set on buttons they will never be reduced, but they may be increased.
- * <p>
- * These are the characters that can be used:
- * <ul>
- * <li><code>'L'</code> - Buttons with this style tag will staticall end up on the left end of the bar.
- * <li><code>'R'</code> - Buttons with this style tag will staticall end up on the right end of the bar.
- * <li><code>'H'</code> - A tag for the "help" button that normally is supposed to be on the right.
- * <li><code>'E'</code> - A tag for the "help2" button that normally is supposed to be on the left.
- * <li><code>'Y'</code> - A tag for the "yes" button.
- * <li><code>'N'</code> - A tag for the "no" button.
- * <li><code>'X'</code> - A tag for the "next >" or "forward >" button.
- * <li><code>'B'</code> - A tag for the "< back>" or "< previous" button.
- * <li><code>'I'</code> - A tag for the "finish".
- * <li><code>'A'</code> - A tag for the "apply" button.
- * <li><code>'C'</code> - A tag for the "cancel" or "close" button.
- * <li><code>'O'</code> - A tag for the "ok" or "done" button.
- * <li><code>'U'</code> - All Uncategorized, Other, or "Unknown" buttons. Tag will be "other".
- * <li><code>'+'</code> - A glue push gap that will take as much space as it can and at least an "unrelated" gap. (Platform dependant)
- * <li><code>'_'</code> - (underscore) An "unrelated" gap. (Platform dependant)
- * </ul>
- * <p>
- * Even though the style tags are normally applied to buttons this works with all components.
- * <p>
- * The normal style for MAC OS X is <code>"L_HE+U+FBI_NYCOA_R"</code> and for Windows is <code>"L_E+U+FBI_YNOCAH_R"</code>
- * @param order The new button order for the current platform.
- */
- public static final void setButtonOrder(String order)
- {
- BUTTON_FORMAT = order;
- MOD_COUNT++;
- }
-
- /** Returns the tag (used in the {@link CC}) for a char. The char is same as used in {@link #getButtonOrder()}.
- * @param c The char. Must be lower case!
- * @return The tag that corresponds to the char or <code>null</code> if the char is unrecognized.
- */
- static final String getTagForChar(char c)
- {
- switch (c) {
- case 'o':
- return "ok";
- case 'c':
- return "cancel";
- case 'h':
- return "help";
- case 'e':
- return "help2";
- case 'y':
- return "yes";
- case 'n':
- return "no";
- case 'a':
- return "apply";
- case 'x':
- return "next"; // a.k.a forward
- case 'b':
- return "back"; // a.k.a. previous
- case 'i':
- return "finish";
- case 'l':
- return "left";
- case 'r':
- return "right";
- case 'u':
- return "other";
- default:
- return null;
- }
- }
-
- /** Returns the platform recommended inter-cell gap in the horizontal (x) dimension..
- * @return The platform recommended inter-cell gap in the horizontal (x) dimension..
- */
- public static BoundSize getGridGapX()
- {
- return DEF_HGAP;
- }
-
- /** Returns the platform recommended inter-cell gap in the vertical (x) dimension..
- * @return The platform recommended inter-cell gap in the vertical (x) dimension..
- */
- public static BoundSize getGridGapY()
- {
- return DEF_VGAP;
- }
-
- /** Returns the default dialog inset depending of the current platform.
- * @param side top == 0, left == 1, bottom = 2, right = 3.
- * @return The inset. Never <code>null</code>.
- */
- public static UnitValue getDialogInsets(int side)
- {
- return DIALOG_INS[side];
- }
-
- /** Sets the default insets for a dialog. Values that are null will not be changed.
- * @param top The top inset. May be <code>null</code>.
- * @param left The left inset. May be <code>null</code>.
- * @param bottom The bottom inset. May be <code>null</code>.
- * @param right The right inset. May be <code>null</code>.
- */
- public static void setDialogInsets(UnitValue top, UnitValue left, UnitValue bottom, UnitValue right)
- {
- if (top != null)
- DIALOG_INS[0] = top;
- if (left != null)
- DIALOG_INS[1] = left;
- if (bottom != null)
- DIALOG_INS[2] = bottom;
- if (right != null)
- DIALOG_INS[3] = right;
-
- MOD_COUNT++;
- }
-
- /** Returns the default panel inset depending of the current platform.
- * @param side top == 0, left == 1, bottom = 2, right = 3.
- * @return The inset. Never <code>null</code>.
- */
- public static UnitValue getPanelInsets(int side)
- {
- return PANEL_INS[side];
- }
-
- /** Sets the default insets for a dialog. Values that are null will not be changed.
- * @param top The top inset. May be <code>null</code>.
- * @param left The left inset. May be <code>null</code>.
- * @param bottom The bottom inset. May be <code>null</code>.
- * @param right The right inset. May be <code>null</code>.
- */
- public static void setPanelInsets(UnitValue top, UnitValue left, UnitValue bottom, UnitValue right)
- {
- if (top != null)
- PANEL_INS[0] = top;
-
- if (left != null)
- PANEL_INS[1] = left;
-
- if (bottom != null)
- PANEL_INS[2] = bottom;
-
- if (right != null)
- PANEL_INS[3] = right;
-
- MOD_COUNT++;
- }
-
- /** Returns the percentage used for alignment for labels (0 is left, 50 is center and 100 is right).
- * @return The percentage used for alignment for labels
- */
- public static float getLabelAlignPercentage()
- {
- return CUR_PLAF == MAC_OSX ? 1f : 0f;
- }
-
- /** Returns the default gap between two components that <b>are in the same cell</b>.
- * @param comp The component that the gap is for. Never <code>null</code>.
- * @param adjacentComp The adjacent component if any. May be <code>null</code>.
- * @param adjacentSide What side the <code>adjacentComp</code> is on. {@link javax.swing.SwingUtilities#TOP} or
- * {@link javax.swing.SwingUtilities#LEFT} or {@link javax.swing.SwingUtilities#BOTTOM} or {@link javax.swing.SwingUtilities#RIGHT}.
- * @param tag The tag string that the component might be tagged with in the component constraints. May be <code>null</code>.
- * @param isLTR If it is left-to-right.
- * @return The default gap between two components or <code>null</code> if there should be no gap.
- */
- static BoundSize getDefaultComponentGap(ComponentWrapper comp, ComponentWrapper adjacentComp, int adjacentSide, String tag, boolean isLTR)
- {
- if (GAP_PROVIDER != null)
- return GAP_PROVIDER.getDefaultGap(comp, adjacentComp, adjacentSide, tag, isLTR);
-
- if (adjacentComp == null)
- return null;
-
-// if (adjacentComp == null || adjacentSide == SwingConstants.LEFT || adjacentSide == SwingConstants.TOP)
-// return null;
-
- return (adjacentSide == SwingConstants.LEFT || adjacentSide == SwingConstants.RIGHT) ? RELATED_X : RELATED_Y;
- }
-
- /** Returns the current gap privider or <code>null</code> if none is set and "related" should always be used.
- * @return The current gap privider or <code>null</code> if none is set and "related" should always be used.
- */
- public static InCellGapProvider getGapProvider()
- {
- return GAP_PROVIDER;
- }
-
- /** Sets the current gap privider or <code>null</code> if none is set and "related" should always be used.
- * @param provider The current gap privider or <code>null</code> if none is set and "related" should always be used.
- */
- public static void setGapProvider(InCellGapProvider provider)
- {
- GAP_PROVIDER = provider;
- }
-
- /** Returns how many times the defaults has been changed. This can be used as a light weight check to
- * see if layout caches needs to be refreshed.
- * @return How many times the defaults has been changed.
- */
- public static int getModCount()
- {
- return MOD_COUNT;
- }
-
- /** Tells all layout manager instances to revalidate and recalculated everything.
- */
- public void invalidate()
- {
- MOD_COUNT++;
- }
-
- /** Returns the current default unit. The default unit is the unit used if no unit is set. E.g. "width 10".
- * @return The current default unit.
- * @see UnitValue#PIXEL
- * @see UnitValue#LPX
- */
- public final static int getDefaultHorizontalUnit()
- {
- return DEF_H_UNIT;
- }
-
- /** Sets the default unit. The default unit is the unit used if no unit is set. E.g. "width 10".
- * @param unit The new default unit.
- * @see UnitValue#PIXEL
- * @see UnitValue#LPX
- */
- public final static void setDefaultHorizontalUnit(int unit)
- {
- if (unit < UnitValue.PIXEL || unit > UnitValue.LABEL_ALIGN)
- throw new IllegalArgumentException("Illegal Unit: " + unit);
-
- if (DEF_H_UNIT != unit) {
- DEF_H_UNIT = unit;
- MOD_COUNT++;
- }
- }
-
- /** Returns the current default unit. The default unit is the unit used if no unit is set. E.g. "width 10".
- * @return The current default unit.
- * @see UnitValue#PIXEL
- * @see UnitValue#LPY
- */
- public final static int getDefaultVerticalUnit()
- {
- return DEF_V_UNIT;
- }
-
- /** Sets the default unit. The default unit is the unit used if no unit is set. E.g. "width 10".
- * @param unit The new default unit.
- * @see UnitValue#PIXEL
- * @see UnitValue#LPY
- */
- public final static void setDefaultVerticalUnit(int unit)
- {
- if (unit < UnitValue.PIXEL || unit > UnitValue.LABEL_ALIGN)
- throw new IllegalArgumentException("Illegal Unit: " + unit);
-
- if (DEF_V_UNIT != unit) {
- DEF_V_UNIT = unit;
- MOD_COUNT++;
- }
- }
+package net.miginfocom.layout; + +import javax.swing.*; +import java.util.HashMap; +/* + * License (BSD): + * ============== + * + * Copyright (c) 2004, Mikael Grev, MiG InfoCom AB. (miglayout (at) miginfocom (dot) com) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright notice, this list + * of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * Neither the name of the MiG InfoCom AB nor the names of its contributors may be + * used to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * @version 1.0 + * @author Mikael Grev, MiG InfoCom AB + * Date: 2006-sep-08 + */ + +/** Currently handles Windows and Mac OS X spacing. + */ +public final class PlatformDefaults +{ + private static int DEF_H_UNIT = UnitValue.LPX; + private static int DEF_V_UNIT = UnitValue.LPY; + + private static InCellGapProvider GAP_PROVIDER = null; + + private static volatile int MOD_COUNT = 0; + + private static final UnitValue LPX4 = new UnitValue(4, UnitValue.LPX, null); + private static final UnitValue LPX7 = new UnitValue(7, UnitValue.LPX, null); + private static final UnitValue LPX8 = new UnitValue(8, UnitValue.LPX, null); + private static final UnitValue LPX9 = new UnitValue(9, UnitValue.LPX, null); + private static final UnitValue LPX10 = new UnitValue(10, UnitValue.LPX, null); + private static final UnitValue LPX11 = new UnitValue(11, UnitValue.LPX, null); + private static final UnitValue LPX12 = new UnitValue(12, UnitValue.LPX, null); + private static final UnitValue LPX14 = new UnitValue(14, UnitValue.LPX, null); + private static final UnitValue LPX16 = new UnitValue(16, UnitValue.LPX, null); + private static final UnitValue LPX20 = new UnitValue(20, UnitValue.LPX, null); + + private static final UnitValue LPY4 = new UnitValue(4, UnitValue.LPY, null); + private static final UnitValue LPY7 = new UnitValue(7, UnitValue.LPY, null); + private static final UnitValue LPY8 = new UnitValue(8, UnitValue.LPY, null); + private static final UnitValue LPY9 = new UnitValue(9, UnitValue.LPY, null); + private static final UnitValue LPY10 = new UnitValue(10, UnitValue.LPY, null); + private static final UnitValue LPY11 = new UnitValue(11, UnitValue.LPY, null); + private static final UnitValue LPY12 = new UnitValue(12, UnitValue.LPY, null); + private static final UnitValue LPY14 = new UnitValue(14, UnitValue.LPY, null); + private static final UnitValue LPY16 = new UnitValue(16, UnitValue.LPY, null); + private static final UnitValue LPY20 = new UnitValue(20, UnitValue.LPY, null); + + public static final int WINDOWS_XP = 0; + public static final int MAC_OSX = 1; +// private static final int GNOME = 2; +// private static final int KDE = 3; + + private static int CUR_PLAF = WINDOWS_XP; + + // Used for holding values. + private final static UnitValue[] PANEL_INS = new UnitValue[4]; + private final static UnitValue[] DIALOG_INS = new UnitValue[4]; + + private static String BUTTON_FORMAT = null; + + private static final HashMap<String, UnitValue> HOR_DEFS = new HashMap<String, UnitValue>(32); + private static final HashMap<String, UnitValue> VER_DEFS = new HashMap<String, UnitValue>(32); + private static BoundSize DEF_VGAP = null, DEF_HGAP = null; + static BoundSize RELATED_X = null, RELATED_Y = null, UNRELATED_X = null, UNRELATED_Y = null; + private static UnitValue BUTT_WIDTH = null; + + private static Float horScale = null, verScale = null; + + /** I value indicating that the size of the font for the container of the component + * will be used as a base for calculating the logical pixel size. This is much as how + * Windows calculated DLU (dialog units). + * @see net.miginfocom.layout.UnitValue#LPX + * @see net.miginfocom.layout.UnitValue#LPY + * @see #setLogicalPixelBase(int) + */ + public static final int BASE_FONT_SIZE = 100; + + /** I value indicating that the screen DPI will be used as a base for calculating the + * logical pixel size. + * <p> + * This is the default value. + * @see net.miginfocom.layout.UnitValue#LPX + * @see net.miginfocom.layout.UnitValue#LPY + * @see #setLogicalPixelBase(int) + * @see #setVerticalScaleFactor(Float) + * @see #setHorizontalScaleFactor(Float) + */ + public static final int BASE_SCALE_FACTOR = 101; + + /** I value indicating that the size of a logica pixel should always be a real pixel + * and thus no compensation will be made. + * @see net.miginfocom.layout.UnitValue#LPX + * @see net.miginfocom.layout.UnitValue#LPY + * @see #setLogicalPixelBase(int) + */ + public static final int BASE_REAL_PIXEL = 102; + + private static int LP_BASE = BASE_SCALE_FACTOR; + + private static int BASE_DPI = 96; + + static { + setPlatform(getCurrentPlatform()); + MOD_COUNT = 0; + } + + /** Returns the platform that the JRE is running on currently. + * @return The platform that the JRE is running on currently. E.g. {@link #MAC_OSX} or {@link #WINDOWS_XP}. + */ + public static int getCurrentPlatform() + { + return System.getProperty("os.name").startsWith("Mac OS") ? MAC_OSX : WINDOWS_XP; + } + + private PlatformDefaults() + { + } + + /** Set the defaults to the default for the platform + * @param plaf The platform. <code>PlatformDefaults.WINDOWS</code> or <code>PlatformDefaults.MAC_OSX</code> + */ + public static void setPlatform(int plaf) + { + if (plaf < WINDOWS_XP || plaf > MAC_OSX) + throw new IllegalArgumentException("Unknown platform: " + plaf); + + CUR_PLAF = plaf; + if (plaf == WINDOWS_XP) { + setRelatedGap(LPX4, LPY4); + setUnrelatedGap(LPX7, LPY9); + setParagraphGap(LPX14, LPY14); + setIndentGap(LPX9, LPY9); + setGridCellGap(LPX4, LPY4); + + setMinimumButtonWidth(new UnitValue(75, UnitValue.LPX, null)); + setButtonOrder("L_E+U+YNBXOCAH_R"); + setDialogInsets(LPY11, LPX11, LPY11, LPX11); + setPanelInsets(LPY7, LPX7, LPY7, LPX7); + BASE_DPI = 96; + } else { + setRelatedGap(LPX8, LPY8); + setUnrelatedGap(LPX12, LPY12); + setParagraphGap(LPX16, LPY16); + setIndentGap(LPX10, LPY10); + setGridCellGap(LPX8, LPY8); + + setMinimumButtonWidth(new UnitValue(68, UnitValue.LPX, null)); + setButtonOrder("L_HE+U+NYBXCOA_R"); + setDialogInsets(LPY14, LPX20, LPY20, LPX20); + setPanelInsets(LPY16, LPX16, LPY16, LPX16); + BASE_DPI = 72; + } + } + + /** Returns the current platform + * @return <code>PlatformDefaults.WINDOWS</code> or <code>PlatformDefaults.MAC_OSX</code> + */ + public static int getPlatform() + { + return CUR_PLAF; + } + + public static int getDefaultDPI() + { + return BASE_DPI; + } + + /** The forced scale factor that all screen relative units (e.g. millimeters, inches and logical pixels) will be multiplied + * with. If <code>null</code> this will default to a scale that will scale the current screen to the default screen resolution + * (72 DPI for Mac and 92 DPI for Windows). + * @return The forced scale or <code>null</code> for default scaling. + * @see #getHorizontalScaleFactor() + * @see ComponentWrapper#getHorizontalScreenDPI() + */ + public static Float + getHorizontalScaleFactor() + { + return horScale; + } + + /** The forced scale factor that all screen relative units (e.g. millimeters, inches and logical pixels) will be multiplied + * with. If <code>null</code> this will default to a scale that will scale the current screen to the default screen resolution + * (72 DPI for Mac and 92 DPI for Windows). + * @param f The forced scale or <code>null</code> for default scaling. + * @see #getHorizontalScaleFactor() + * @see ComponentWrapper#getHorizontalScreenDPI() + */ + public static void setHorizontalScaleFactor(Float f) + { + if (horScale != f) { + horScale = f; + MOD_COUNT++; + } + } + + /** The forced scale factor that all screen relative units (e.g. millimeters, inches and logical pixels) will be multiplied + * with. If <code>null</code> this will default to a scale that will scale the current screen to the default screen resolution + * (72 DPI for Mac and 92 DPI for Windows). + * @return The forced scale or <code>null</code> for default scaling. + * @see #getHorizontalScaleFactor() + * @see ComponentWrapper#getVerticalScreenDPI() + */ + public static Float getVerticalScaleFactor() + { + return verScale; + } + + /** The forced scale factor that all screen relative units (e.g. millimeters, inches and logical pixels) will be multiplied + * with. If <code>null</code> this will default to a scale that will scale the current screen to the default screen resolution + * (72 DPI for Mac and 92 DPI for Windows). + * @param f The forced scale or <code>null</code> for default scaling. + * @see #getHorizontalScaleFactor() + * @see ComponentWrapper#getVerticalScreenDPI() + */ + public static void setVerticalScaleFactor(Float f) + { + if (verScale != f) { + verScale = f; + MOD_COUNT++; + } + } + + /** What base value should be used to calculate logical pixel sizes. + * @return The current base. Default is {@link #BASE_SCALE_FACTOR} + * @see #BASE_FONT_SIZE + * @see # BASE_SCREEN_DPI_FACTOR + * @see #BASE_REAL_PIXEL + */ + public static int getLogicalPixelBase() + { + return LP_BASE; + } + + /** What base value should be used to calculate logical pixel sizes. + * @param base The new base. Default is {@link #BASE_SCALE_FACTOR} + * @see #BASE_FONT_SIZE + * @see # BASE_SCREEN_DPI_FACTOR + * @see #BASE_REAL_PIXEL + */ + public static void setLogicalPixelBase(int base) + { + if (LP_BASE != base) { + if (base < BASE_FONT_SIZE || base > BASE_SCALE_FACTOR) + throw new IllegalArgumentException("Unrecognized base: " + base); + + LP_BASE = base; + MOD_COUNT++; + } + } + + /** Sets gap value for components that are "related". + * @param x The value that will be transformed to pixels. If <code>null</code> the current value will not change. + * @param y The value that will be transformed to pixels. If <code>null</code> the current value will not change. + */ + public static void setRelatedGap(UnitValue x, UnitValue y) + { + setUnitValue(new String[] {"r", "rel", "related"}, x, y); + + RELATED_X = new BoundSize(x, x, null, "rel:rel"); + RELATED_Y = new BoundSize(y, y, null, "rel:rel"); + } + + /** Sets gap value for components that are "unrelated". + * @param x The value that will be transformed to pixels. If <code>null</code> the current value will not change. + * @param y The value that will be transformed to pixels. If <code>null</code> the current value will not change. + */ + public static void setUnrelatedGap(UnitValue x, UnitValue y) + { + setUnitValue(new String[] {"u", "unrel", "unrelated"}, x, y); + + UNRELATED_X = new BoundSize(x, x, null, "unrel:unrel"); + UNRELATED_Y = new BoundSize(y, y, null, "unrel:unrel"); + } + + /** Sets paragraph gap value for components. + * @param x The value that will be transformed to pixels. If <code>null</code> the current value will not change. + * @param y The value that will be transformed to pixels. If <code>null</code> the current value will not change. + */ + public static void setParagraphGap(UnitValue x, UnitValue y) + { + setUnitValue(new String[] {"p", "para", "paragraph"}, x, y); + } + + /** Sets gap value for components that are "intended". + * @param x The value that will be transformed to pixels. If <code>null</code> the current value will not change. + * @param y The value that will be transformed to pixels. If <code>null</code> the current value will not change. + */ + public static void setIndentGap(UnitValue x, UnitValue y) + { + setUnitValue(new String[] {"i", "ind", "indent"}, x, y); + } + + /** Sets gap between two cells in the grid. Note that this is not a gap between component IN a cell, that has to be set + * on the component constraints. The value will be the min and preferred size of the gap. + * @param x The value that will be transformed to pixels. If <code>null</code> the current value will not change. + * @param y The value that will be transformed to pixels. If <code>null</code> the current value will not change. + */ + public static void setGridCellGap(UnitValue x, UnitValue y) + { + if (x != null) + DEF_HGAP = new BoundSize(x, x, null, null); + + if (y != null) + DEF_VGAP = new BoundSize(y, y, null, null); + + MOD_COUNT++; + } + + /** Sets the recommended minimum button width. + * @param width The recommended minimum button width. + */ + public static void setMinimumButtonWidth(UnitValue width) + { + BUTT_WIDTH = width; + MOD_COUNT++; + } + + /** Returns the recommended minimum button width depending on the current set platform. + * @return The recommended minimum button width depending on the current set platform. + */ + public static UnitValue getMinimumButtonWidth() + { + return BUTT_WIDTH; + } + + /** Returns the unit value associated with the unit. (E.i. "related" or "indent"). Must be lower case. + * @param unit The unit string. + * @return Tthe unit value associated with the unit. <code>null</code> for unrecognized units. + */ + public static UnitValue getUnitValueX(String unit) + { + return HOR_DEFS.get(unit); + } + + /** Returns the unit value associated with the unit. (E.i. "related" or "indent"). Must be lower case. + * @param unit The unit string. + * @return Tthe unit value associated with the unit. <code>null</code> for unrecognized units. + */ + public static UnitValue getUnitValueY(String unit) + { + return VER_DEFS.get(unit); + } + + /** Sets the unit value assiciated with a unit string. This may be used to store values for new unit strings + * or modify old. Note that if a built in unit (such as "related") is modified all versions of it must be + * set (I.e. "r", "rel" and "related"). The build in values will be reset to the default ones if the platform + * is re-set. + * @param unitStrings The unit strings. E.g. "mu", "myunit". Will be converted to lower case and trimmed. Not <code>null</code>. + * @param x The value for the horizontal dimension. If <code>null</code> the value is not changed. + * @param y The value for the vertical dimension. Might be same object as for <code>x</code>. If <code>null</code> the value is not changed. + */ + public static final void setUnitValue(String[] unitStrings, UnitValue x, UnitValue y) + { + for (int i = 0; i < unitStrings.length; i++) { + String s = unitStrings[i].toLowerCase().trim(); + if (x != null) + HOR_DEFS.put(s, x); + if (y != null) + VER_DEFS.put(s, y); + } + MOD_COUNT++; + } + + /** Understands ("r", "rel", "related") OR ("u", "unrel", "unrelated") OR ("i", "ind", "indent") OR ("p", "para", "paragraph"). + */ + static final int convertToPixels(float value, String unit, boolean isHor, float ref, ContainerWrapper parent, ComponentWrapper comp) + { + UnitValue uv = (isHor ? HOR_DEFS : VER_DEFS).get(unit); + return uv != null ? Math.round(value * uv.getPixels(ref, parent, comp)) : UnitConverter.UNABLE; + } + + /** Returns the order for the typical buttons in a standard button bar. It is one letter per button type. + * @return The button order. + * @see #setButtonOrder(String) + */ + public static final String getButtonOrder() + { + return BUTTON_FORMAT; + } + + /** Sets the order for the typical buttons in a standard button bar. It is one letter per button type. + * <p> + * Letter in upper case will get the minimum button width that the {@link #getMinimumButtonWidth()} specifies + * and letters in lower case will get the width the corrent look&feel specifies. + * <p> + * Gaps will never be added to before the first component or after the last component. However, '+' (push) will be + * applied before and after as well, but with a minimum size of 0 if first/last so there will not be a gap + * before or after. + * <p> + * If gaps are explicitly set on buttons they will never be reduced, but they may be increased. + * <p> + * These are the characters that can be used: + * <ul> + * <li><code>'L'</code> - Buttons with this style tag will staticall end up on the left end of the bar. + * <li><code>'R'</code> - Buttons with this style tag will staticall end up on the right end of the bar. + * <li><code>'H'</code> - A tag for the "help" button that normally is supposed to be on the right. + * <li><code>'E'</code> - A tag for the "help2" button that normally is supposed to be on the left. + * <li><code>'Y'</code> - A tag for the "yes" button. + * <li><code>'N'</code> - A tag for the "no" button. + * <li><code>'X'</code> - A tag for the "next >" or "forward >" button. + * <li><code>'B'</code> - A tag for the "< back>" or "< previous" button. + * <li><code>'I'</code> - A tag for the "finish". + * <li><code>'A'</code> - A tag for the "apply" button. + * <li><code>'C'</code> - A tag for the "cancel" or "close" button. + * <li><code>'O'</code> - A tag for the "ok" or "done" button. + * <li><code>'U'</code> - All Uncategorized, Other, or "Unknown" buttons. Tag will be "other". + * <li><code>'+'</code> - A glue push gap that will take as much space as it can and at least an "unrelated" gap. (Platform dependant) + * <li><code>'_'</code> - (underscore) An "unrelated" gap. (Platform dependant) + * </ul> + * <p> + * Even though the style tags are normally applied to buttons this works with all components. + * <p> + * The normal style for MAC OS X is <code>"L_HE+U+FBI_NYCOA_R"</code> and for Windows is <code>"L_E+U+FBI_YNOCAH_R"</code> + * @param order The new button order for the current platform. + */ + public static final void setButtonOrder(String order) + { + BUTTON_FORMAT = order; + MOD_COUNT++; + } + + /** Returns the tag (used in the {@link CC}) for a char. The char is same as used in {@link #getButtonOrder()}. + * @param c The char. Must be lower case! + * @return The tag that corresponds to the char or <code>null</code> if the char is unrecognized. + */ + static final String getTagForChar(char c) + { + switch (c) { + case 'o': + return "ok"; + case 'c': + return "cancel"; + case 'h': + return "help"; + case 'e': + return "help2"; + case 'y': + return "yes"; + case 'n': + return "no"; + case 'a': + return "apply"; + case 'x': + return "next"; // a.k.a forward + case 'b': + return "back"; // a.k.a. previous + case 'i': + return "finish"; + case 'l': + return "left"; + case 'r': + return "right"; + case 'u': + return "other"; + default: + return null; + } + } + + /** Returns the platform recommended inter-cell gap in the horizontal (x) dimension.. + * @return The platform recommended inter-cell gap in the horizontal (x) dimension.. + */ + public static BoundSize getGridGapX() + { + return DEF_HGAP; + } + + /** Returns the platform recommended inter-cell gap in the vertical (x) dimension.. + * @return The platform recommended inter-cell gap in the vertical (x) dimension.. + */ + public static BoundSize getGridGapY() + { + return DEF_VGAP; + } + + /** Returns the default dialog inset depending of the current platform. + * @param side top == 0, left == 1, bottom = 2, right = 3. + * @return The inset. Never <code>null</code>. + */ + public static UnitValue getDialogInsets(int side) + { + return DIALOG_INS[side]; + } + + /** Sets the default insets for a dialog. Values that are null will not be changed. + * @param top The top inset. May be <code>null</code>. + * @param left The left inset. May be <code>null</code>. + * @param bottom The bottom inset. May be <code>null</code>. + * @param right The right inset. May be <code>null</code>. + */ + public static void setDialogInsets(UnitValue top, UnitValue left, UnitValue bottom, UnitValue right) + { + if (top != null) + DIALOG_INS[0] = top; + if (left != null) + DIALOG_INS[1] = left; + if (bottom != null) + DIALOG_INS[2] = bottom; + if (right != null) + DIALOG_INS[3] = right; + + MOD_COUNT++; + } + + /** Returns the default panel inset depending of the current platform. + * @param side top == 0, left == 1, bottom = 2, right = 3. + * @return The inset. Never <code>null</code>. + */ + public static UnitValue getPanelInsets(int side) + { + return PANEL_INS[side]; + } + + /** Sets the default insets for a dialog. Values that are null will not be changed. + * @param top The top inset. May be <code>null</code>. + * @param left The left inset. May be <code>null</code>. + * @param bottom The bottom inset. May be <code>null</code>. + * @param right The right inset. May be <code>null</code>. + */ + public static void setPanelInsets(UnitValue top, UnitValue left, UnitValue bottom, UnitValue right) + { + if (top != null) + PANEL_INS[0] = top; + + if (left != null) + PANEL_INS[1] = left; + + if (bottom != null) + PANEL_INS[2] = bottom; + + if (right != null) + PANEL_INS[3] = right; + + MOD_COUNT++; + } + + /** Returns the percentage used for alignment for labels (0 is left, 50 is center and 100 is right). + * @return The percentage used for alignment for labels + */ + public static float getLabelAlignPercentage() + { + return CUR_PLAF == MAC_OSX ? 1f : 0f; + } + + /** Returns the default gap between two components that <b>are in the same cell</b>. + * @param comp The component that the gap is for. Never <code>null</code>. + * @param adjacentComp The adjacent component if any. May be <code>null</code>. + * @param adjacentSide What side the <code>adjacentComp</code> is on. {@link javax.swing.SwingUtilities#TOP} or + * {@link javax.swing.SwingUtilities#LEFT} or {@link javax.swing.SwingUtilities#BOTTOM} or {@link javax.swing.SwingUtilities#RIGHT}. + * @param tag The tag string that the component might be tagged with in the component constraints. May be <code>null</code>. + * @param isLTR If it is left-to-right. + * @return The default gap between two components or <code>null</code> if there should be no gap. + */ + static BoundSize getDefaultComponentGap(ComponentWrapper comp, ComponentWrapper adjacentComp, int adjacentSide, String tag, boolean isLTR) + { + if (GAP_PROVIDER != null) + return GAP_PROVIDER.getDefaultGap(comp, adjacentComp, adjacentSide, tag, isLTR); + + if (adjacentComp == null) + return null; + +// if (adjacentComp == null || adjacentSide == SwingConstants.LEFT || adjacentSide == SwingConstants.TOP) +// return null; + + return (adjacentSide == SwingConstants.LEFT || adjacentSide == SwingConstants.RIGHT) ? RELATED_X : RELATED_Y; + } + + /** Returns the current gap privider or <code>null</code> if none is set and "related" should always be used. + * @return The current gap privider or <code>null</code> if none is set and "related" should always be used. + */ + public static InCellGapProvider getGapProvider() + { + return GAP_PROVIDER; + } + + /** Sets the current gap privider or <code>null</code> if none is set and "related" should always be used. + * @param provider The current gap privider or <code>null</code> if none is set and "related" should always be used. + */ + public static void setGapProvider(InCellGapProvider provider) + { + GAP_PROVIDER = provider; + } + + /** Returns how many times the defaults has been changed. This can be used as a light weight check to + * see if layout caches needs to be refreshed. + * @return How many times the defaults has been changed. + */ + public static int getModCount() + { + return MOD_COUNT; + } + + /** Tells all layout manager instances to revalidate and recalculated everything. + */ + public void invalidate() + { + MOD_COUNT++; + } + + /** Returns the current default unit. The default unit is the unit used if no unit is set. E.g. "width 10". + * @return The current default unit. + * @see UnitValue#PIXEL + * @see UnitValue#LPX + */ + public final static int getDefaultHorizontalUnit() + { + return DEF_H_UNIT; + } + + /** Sets the default unit. The default unit is the unit used if no unit is set. E.g. "width 10". + * @param unit The new default unit. + * @see UnitValue#PIXEL + * @see UnitValue#LPX + */ + public final static void setDefaultHorizontalUnit(int unit) + { + if (unit < UnitValue.PIXEL || unit > UnitValue.LABEL_ALIGN) + throw new IllegalArgumentException("Illegal Unit: " + unit); + + if (DEF_H_UNIT != unit) { + DEF_H_UNIT = unit; + MOD_COUNT++; + } + } + + /** Returns the current default unit. The default unit is the unit used if no unit is set. E.g. "width 10". + * @return The current default unit. + * @see UnitValue#PIXEL + * @see UnitValue#LPY + */ + public final static int getDefaultVerticalUnit() + { + return DEF_V_UNIT; + } + + /** Sets the default unit. The default unit is the unit used if no unit is set. E.g. "width 10". + * @param unit The new default unit. + * @see UnitValue#PIXEL + * @see UnitValue#LPY + */ + public final static void setDefaultVerticalUnit(int unit) + { + if (unit < UnitValue.PIXEL || unit > UnitValue.LABEL_ALIGN) + throw new IllegalArgumentException("Illegal Unit: " + unit); + + if (DEF_V_UNIT != unit) { + DEF_V_UNIT = unit; + MOD_COUNT++; + } + } }
\ No newline at end of file diff --git a/prototypes/miglayout/net/miginfocom/layout/ResizeConstraint.java b/prototypes/miglayout/net/miginfocom/layout/ResizeConstraint.java index 75a4c376..c02ad0f8 100644 --- a/prototypes/miglayout/net/miginfocom/layout/ResizeConstraint.java +++ b/prototypes/miglayout/net/miginfocom/layout/ResizeConstraint.java @@ -1,92 +1,92 @@ -package net.miginfocom.layout;
-
-import java.io.*;
-/*
- * License (BSD):
- * ==============
- *
- * Copyright (c) 2004, Mikael Grev, MiG InfoCom AB. (miglayout (at) miginfocom (dot) com)
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification,
- * are permitted provided that the following conditions are met:
- * Redistributions of source code must retain the above copyright notice, this list
- * of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above copyright notice, this
- * list of conditions and the following disclaimer in the documentation and/or other
- * materials provided with the distribution.
- * Neither the name of the MiG InfoCom AB nor the names of its contributors may be
- * used to endorse or promote products derived from this software without specific
- * prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
- * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
- * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
- * OF SUCH DAMAGE.
- *
- * @version 1.0
- * @author Mikael Grev, MiG InfoCom AB
- * Date: 2006-sep-08
- */
-
-/** A parsed constraint that specifies how an entity (normally column/row or component) can shrink or
- * grow compared to other entities.
- */
-final class ResizeConstraint implements Externalizable
-{
- static final Float WEIGHT_100 = new Float(100);
-
- /** How flexilble the entity should be, relative to other entities, when it comes to growing. <code>null</code> or
- * zero mean it will never grow. An entity that has twise the growWeight compared to another entity will get twice
- * as much of available space.
- * <p>
- * "grow" are only compared within the same "growPrio".
- */
- Float grow = null;
-
- /** The relative priority used for determining which entities gets the extra space first.
- */
- int growPrio = 100;
-
- Float shrink = WEIGHT_100;
-
- int shrinkPrio = 100;
-
- public ResizeConstraint() // For Externalizable
- {
- }
-
- ResizeConstraint(int shrinkPrio, Float shrinkWeight, int growPrio, Float growWeight)
- {
- this.shrinkPrio = shrinkPrio;
- this.shrink = shrinkWeight;
- this.growPrio = growPrio;
- this.grow = growWeight;
- }
-
- // ************************************************
- // Persistence Delegate and Serializable combined.
- // ************************************************
-
- private Object readResolve() throws ObjectStreamException
- {
- return LayoutUtil.getSerializedObject(this);
- }
-
- public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException
- {
- LayoutUtil.setSerializedObject(this, LayoutUtil.readAsXML(in));
- }
-
- public void writeExternal(ObjectOutput out) throws IOException
- {
- if (getClass() == ResizeConstraint.class)
- LayoutUtil.writeAsXML(out, this);
- }
-}
+package net.miginfocom.layout; + +import java.io.*; +/* + * License (BSD): + * ============== + * + * Copyright (c) 2004, Mikael Grev, MiG InfoCom AB. (miglayout (at) miginfocom (dot) com) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright notice, this list + * of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * Neither the name of the MiG InfoCom AB nor the names of its contributors may be + * used to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * @version 1.0 + * @author Mikael Grev, MiG InfoCom AB + * Date: 2006-sep-08 + */ + +/** A parsed constraint that specifies how an entity (normally column/row or component) can shrink or + * grow compared to other entities. + */ +final class ResizeConstraint implements Externalizable +{ + static final Float WEIGHT_100 = new Float(100); + + /** How flexilble the entity should be, relative to other entities, when it comes to growing. <code>null</code> or + * zero mean it will never grow. An entity that has twise the growWeight compared to another entity will get twice + * as much of available space. + * <p> + * "grow" are only compared within the same "growPrio". + */ + Float grow = null; + + /** The relative priority used for determining which entities gets the extra space first. + */ + int growPrio = 100; + + Float shrink = WEIGHT_100; + + int shrinkPrio = 100; + + public ResizeConstraint() // For Externalizable + { + } + + ResizeConstraint(int shrinkPrio, Float shrinkWeight, int growPrio, Float growWeight) + { + this.shrinkPrio = shrinkPrio; + this.shrink = shrinkWeight; + this.growPrio = growPrio; + this.grow = growWeight; + } + + // ************************************************ + // Persistence Delegate and Serializable combined. + // ************************************************ + + private Object readResolve() throws ObjectStreamException + { + return LayoutUtil.getSerializedObject(this); + } + + public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException + { + LayoutUtil.setSerializedObject(this, LayoutUtil.readAsXML(in)); + } + + public void writeExternal(ObjectOutput out) throws IOException + { + if (getClass() == ResizeConstraint.class) + LayoutUtil.writeAsXML(out, this); + } +} diff --git a/prototypes/miglayout/net/miginfocom/layout/UnitConverter.java b/prototypes/miglayout/net/miginfocom/layout/UnitConverter.java index e94e82bd..3a03ea2a 100644 --- a/prototypes/miglayout/net/miginfocom/layout/UnitConverter.java +++ b/prototypes/miglayout/net/miginfocom/layout/UnitConverter.java @@ -1,59 +1,59 @@ -package net.miginfocom.layout;
-/*
- * License (BSD):
- * ==============
- *
- * Copyright (c) 2004, Mikael Grev, MiG InfoCom AB. (miglayout (at) miginfocom (dot) com)
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification,
- * are permitted provided that the following conditions are met:
- * Redistributions of source code must retain the above copyright notice, this list
- * of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above copyright notice, this
- * list of conditions and the following disclaimer in the documentation and/or other
- * materials provided with the distribution.
- * Neither the name of the MiG InfoCom AB nor the names of its contributors may be
- * used to endorse or promote products derived from this software without specific
- * prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
- * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
- * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
- * OF SUCH DAMAGE.
- *
- * @version 1.0
- * @author Mikael Grev, MiG InfoCom AB
- * Date: 2006-sep-08
- */
-
-/**
- */
-public abstract class UnitConverter
-{
- /** Value to return if this converter can not handle the <code>unit</code> sent in as an argument
- * to the convert method.
- */
- public static final int UNABLE = -87654312;
-
- /** Converts <code>value</code> to pixels.
- * @param value The value to be converted.
- * @param unit The unit of <code>value</code>. Never <code>null</code> and at least one character.
- * @param refValue Some reference value that may of may not be used. If the unit is percent for instance this value
- * is the value to take the percent from. Usually the size of the parent component in the appropriate dimension.
- * @param isHor If the value is horizontal (<code>true</code>) or vertical (<code>false</code>).
- * @param parent The parent of the target component that <code>value</code> is to be applied to.
- * Might for instance be needed to get the screen that the component is on in a multi screen environment.
- * <p>
- * May be <code>null</code> in which case a "best guess" value should be returned.
- * @param comp The component, if applicable, or <code>null</code> if none.
- * @return The number of pixels if <code>unit</code> is handled by this converter, <code>UnitConverter.UNABLE</code> if not.
- */
- public abstract int convertToPixels(float value, String unit, boolean isHor, float refValue, ContainerWrapper parent, ComponentWrapper comp);
-}
+package net.miginfocom.layout; +/* + * License (BSD): + * ============== + * + * Copyright (c) 2004, Mikael Grev, MiG InfoCom AB. (miglayout (at) miginfocom (dot) com) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright notice, this list + * of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * Neither the name of the MiG InfoCom AB nor the names of its contributors may be + * used to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * @version 1.0 + * @author Mikael Grev, MiG InfoCom AB + * Date: 2006-sep-08 + */ + +/** + */ +public abstract class UnitConverter +{ + /** Value to return if this converter can not handle the <code>unit</code> sent in as an argument + * to the convert method. + */ + public static final int UNABLE = -87654312; + + /** Converts <code>value</code> to pixels. + * @param value The value to be converted. + * @param unit The unit of <code>value</code>. Never <code>null</code> and at least one character. + * @param refValue Some reference value that may of may not be used. If the unit is percent for instance this value + * is the value to take the percent from. Usually the size of the parent component in the appropriate dimension. + * @param isHor If the value is horizontal (<code>true</code>) or vertical (<code>false</code>). + * @param parent The parent of the target component that <code>value</code> is to be applied to. + * Might for instance be needed to get the screen that the component is on in a multi screen environment. + * <p> + * May be <code>null</code> in which case a "best guess" value should be returned. + * @param comp The component, if applicable, or <code>null</code> if none. + * @return The number of pixels if <code>unit</code> is handled by this converter, <code>UnitConverter.UNABLE</code> if not. + */ + public abstract int convertToPixels(float value, String unit, boolean isHor, float refValue, ContainerWrapper parent, ComponentWrapper comp); +} diff --git a/prototypes/miglayout/net/miginfocom/layout/UnitValue.java b/prototypes/miglayout/net/miginfocom/layout/UnitValue.java index aa12ac3e..e4da114e 100644 --- a/prototypes/miglayout/net/miginfocom/layout/UnitValue.java +++ b/prototypes/miglayout/net/miginfocom/layout/UnitValue.java @@ -1,626 +1,626 @@ -package net.miginfocom.layout;
-/*
- * License (BSD):
- * ==============
- *
- * Copyright (c) 2004, Mikael Grev, MiG InfoCom AB. (miglayout (at) miginfocom (dot) com)
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification,
- * are permitted provided that the following conditions are met:
- * Redistributions of source code must retain the above copyright notice, this list
- * of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above copyright notice, this
- * list of conditions and the following disclaimer in the documentation and/or other
- * materials provided with the distribution.
- * Neither the name of the MiG InfoCom AB nor the names of its contributors may be
- * used to endorse or promote products derived from this software without specific
- * prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
- * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
- * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
- * OF SUCH DAMAGE.
- *
- * @version 1.0
- * @author Mikael Grev, MiG InfoCom AB
- * Date: 2006-sep-08
- */
-
-import java.beans.Encoder;
-import java.beans.Expression;
-import java.beans.PersistenceDelegate;
-import java.io.*;
-import java.util.ArrayList;
-import java.util.HashMap;
-
-public final class UnitValue implements Serializable
-{
- private static final HashMap<String, Integer> UNIT_MAP = new HashMap<String, Integer>(32);
-
- private static final ArrayList<UnitConverter> CONVERTERS = new ArrayList<UnitConverter>();
-
- /** An operation indicating a static value.
- */
- public static final int STATIC = 100;
-
- /** An operation indicating a addition of two sub units.
- */
- public static final int ADD = 101; // Must have "sub-unit values"
-
- /** An operation indicating a subtraction of two sub units
- */
- public static final int SUB = 102; // Must have "sub-unit values"
-
- /** An operation indicating a multiplication of two sub units.
- */
- public static final int MUL = 103; // Must have "sub-unit values"
-
- /** An operation indicating a division of two sub units.
- */
- public static final int DIV = 104; // Must have "sub-unit values"
-
- /** An operation indicating the minimum of two sub units
- */
- public static final int MIN = 105; // Must have "sub-unit values"
-
- /** An operation indicating the maximum of two sub units
- */
- public static final int MAX = 106; // Must have "sub-unit values"
-
- /** An operation indicating the middle value of two sub units
- */
- public static final int MID = 107; // Must have "sub-unit values"
-
-
-
-
- /** A unit indicating pixels.
- */
- public static final int PIXEL = 0;
-
- /** A unit indicating logical horizontal pixels.
- */
- public static final int LPX = 1;
-
- /** A unit indicating logical vertical pixels.
- */
- public static final int LPY = 2;
-
- /** A unit indicating millimeters.
- */
- public static final int MM = 3;
-
- /** A unit indicating centimeters.
- */
- public static final int CM = 4;
-
- /** A unit indicating inches.
- */
- public static final int INCH = 5;
-
- /** A unit indicating percent.
- */
- public static final int PERCENT = 6;
-
- /** A unit indicating points.
- */
- public static final int PT = 7;
-
- /** A unit indicating screen width in pixels.
- */
- public static final int SPX = 8;
-
- /** A unit indicating screen height in pixels.
- */
- public static final int SPY = 9;
-
- /** A unit indicating alignment.
- */
- public static final int ALIGN = 12;
-
- /** A unit indicating minimum size.
- */
- public static final int MIN_SIZE = 13;
-
- /** A unit indicating preferred size.
- */
- public static final int PREF_SIZE = 14;
-
- /** A unit indicating maximum size.
- */
- public static final int MAX_SIZE = 15;
-
- /** A unit indicating botton size.
- */
- public static final int BUTTON = 16;
-
- /** A unit indicating linking to x.
- */
- public static final int LINK_X = 18; // First link
-
- /** A unit indicating linking to y.
- */
- public static final int LINK_Y = 19;
-
- /** A unit indicating linking to width.
- */
- public static final int LINK_W = 20;
-
- /** A unit indicating linking to height.
- */
- public static final int LINK_H = 21;
-
- /** A unit indicating linking to x2.
- */
- public static final int LINK_X2 = 22;
-
- /** A unit indicating linking to y2.
- */
- public static final int LINK_Y2 = 23;
-
- /** A unit indicating linking to x position on screen.
- */
- public static final int LINK_XPOS = 24;
-
- /** A unit indicating linking to y position on screen.
- */
- public static final int LINK_YPOS = 25; // Last link
-
- /** A unit indicating a lookup.
- */
- public static final int LOOKUP = 26;
-
- /** A unit indicating label alignment.
- */
- public static final int LABEL_ALIGN = 27;
-
- private static final int IDENTITY = -1;
-
- static {
- UNIT_MAP.put("px", new Integer(PIXEL));
- UNIT_MAP.put("lpx", new Integer(LPX));
- UNIT_MAP.put("lpy", new Integer(LPY));
- UNIT_MAP.put("%", new Integer(PERCENT));
- UNIT_MAP.put("cm", new Integer(CM));
- UNIT_MAP.put("in", new Integer(INCH));
- UNIT_MAP.put("spx", new Integer(SPX));
- UNIT_MAP.put("spy", new Integer(SPY));
- UNIT_MAP.put("al", new Integer(ALIGN));
- UNIT_MAP.put("mm", new Integer(MM));
- UNIT_MAP.put("pt", new Integer(PT));
- UNIT_MAP.put("min", new Integer(MIN_SIZE));
- UNIT_MAP.put("minimum", new Integer(MIN_SIZE));
- UNIT_MAP.put("p", new Integer(PREF_SIZE));
- UNIT_MAP.put("pref", new Integer(PREF_SIZE));
- UNIT_MAP.put("max", new Integer(MAX_SIZE));
- UNIT_MAP.put("maximum", new Integer(MAX_SIZE));
- UNIT_MAP.put("button", new Integer(BUTTON));
- UNIT_MAP.put("label", new Integer(LABEL_ALIGN));
- }
-
- static final UnitValue ZERO = new UnitValue(0, null, PIXEL, true, STATIC, null, null, "0px");
- static final UnitValue TOP = new UnitValue(0, null, PERCENT, false, STATIC, null, null, "top");
- static final UnitValue LEADING = new UnitValue(0, null, PERCENT, true, STATIC, null, null, "leading");
- static final UnitValue LEFT = new UnitValue(0, null, PERCENT, true, STATIC, null, null, "left");
- static final UnitValue CENTER = new UnitValue(50, null, PERCENT, true, STATIC, null, null, "center");
- static final UnitValue TRAILING = new UnitValue(100, null, PERCENT, true, STATIC, null, null, "trailing");
- static final UnitValue RIGHT = new UnitValue(100, null, PERCENT, true, STATIC, null, null, "right");
- static final UnitValue BOTTOM = new UnitValue(100, null, PERCENT, false, STATIC, null, null, "bottom");
- static final UnitValue LABEL = new UnitValue(0, null, LABEL_ALIGN, false, STATIC, null, null, "label");
-
- static final UnitValue INF = new UnitValue(LayoutUtil.INF, null, PIXEL, true, STATIC, null, null, "inf");
-
- static final UnitValue BASELINE_IDENTITY = new UnitValue(0, null, IDENTITY, false, STATIC, null, null, "baseline");
-
- private final transient float value;
- private final transient int unit;
- private final transient int oper;
- private final transient String unitStr;
- private final transient boolean isHor;
- private final transient UnitValue[] subUnits;
-
- // Pixel
- public UnitValue(float value) // If hor/ver does not matter.
- {
- this(value, null, PIXEL, true, STATIC, null, null, value + "px");
- }
-
- public UnitValue(float value, int unit, String createString) // If hor/ver does not matter.
- {
- this(value, null, unit, true, STATIC, null, null, createString);
- }
-
- UnitValue(float value, String unitStr, boolean isHor, int oper, String createString)
- {
- this(value, unitStr, -1, isHor, oper, null, null, createString);
- }
-
- UnitValue(boolean isHor, int oper, UnitValue sub1, UnitValue sub2, String createString)
- {
- this(0, "", -1, isHor, oper, sub1, sub2, createString);
- if (sub1 == null || sub2 == null)
- throw new IllegalArgumentException("Sub units is null!");
- }
-
- private UnitValue(float value, String unitStr, int unit, boolean isHor, int oper, UnitValue sub1, UnitValue sub2, String createString)
- {
- if (oper < STATIC || oper > MID)
- throw new IllegalArgumentException("Unknown Operation: " + oper);
-
- if (oper >= ADD && oper <= MID && (sub1 == null || sub2 == null))
- throw new IllegalArgumentException(oper + " Operation may not have null sub-UnitValues.");
-
- this.value = value;
- this.oper = oper;
- this.isHor = isHor;
- this.unitStr = unitStr;
- this.unit = unitStr != null ? parseUnitString() : unit;
- this.subUnits = sub1 != null && sub2 != null ? new UnitValue[] {sub1, sub2} : null;
-
- LayoutUtil.putCCString(this, createString); // "this" escapes!! Safe though.
- }
-
- /** Returns the size in pixels rounded.
- * @param refValue The reference value. Normally the size of the parent. For unit {@link #ALIGN} the current size of the component should be sent in.
- * @param parent The parent. May be <code>null</code> for testing the validity of the value, but should normally not and are not
- * required to return any usable value if <code>null</code>.
- * @param comp The component, if any, that the value is for. Might be <code>null</code> if the value is not
- * connected to any component.
- * @return The size in pixels.
- */
- public final int getPixels(float refValue, ContainerWrapper parent, ComponentWrapper comp)
- {
- return Math.round(getPixelsExact(refValue, parent, comp));
- }
-
- private static final float[] SCALE = new float[] {25.4f, 2.54f, 1f, 0f, 72f};
- /** Returns the size in pixels.
- * @param refValue The reference value. Normally the size of the parent. For unit {@link #ALIGN} the current size of the component should be sent in.
- * @param parent The parent. May be <code>null</code> for testing the validity of the value, but should normally not and are not
- * required to return any usable value if <code>null</code>.
- * @param comp The component, if any, that the value is for. Might be <code>null</code> if the value is not
- * connected to any component.
- * @return The size in pixels.
- */
- public final float getPixelsExact(float refValue, ContainerWrapper parent, ComponentWrapper comp)
- {
- if (parent == null)
- return 1;
-
- if (oper == STATIC) {
- switch (unit) {
- case PIXEL:
- return value;
-
- case LPX:
- case LPY:
- return parent.getPixelUnitFactor(unit == LPX) * value;
-
- case MM:
- case CM:
- case INCH:
- case PT:
- float f = SCALE[unit - MM];
- Float s = isHor ? PlatformDefaults.getHorizontalScaleFactor() : PlatformDefaults.getVerticalScaleFactor();
- if (s != null)
- f *= s.floatValue();
- return (isHor ? parent.getHorizontalScreenDPI() : parent.getVerticalScreenDPI()) * value / f;
-
- case PERCENT:
- return value * refValue * 0.01f;
-
- case SPX:
- case SPY:
- return (unit == SPX ? parent.getScreenWidth() : parent.getScreenHeight()) * value * 0.01f;
-
- case ALIGN:
- Integer st = LinkHandler.getValue(parent.getLayout(), "visual", isHor ? LinkHandler.X : LinkHandler.Y);
- Integer sz = LinkHandler.getValue(parent.getLayout(), "visual", isHor ? LinkHandler.WIDTH : LinkHandler.HEIGHT);
- if (st == null || sz == null)
- return 0;
- return value * (Math.max(0, sz.intValue()) - refValue) + st.intValue();
-
- case MIN_SIZE:
- if (comp == null)
- return 0;
- return isHor ? comp.getMinimumWidth() : comp.getMinimumHeight();
-
- case PREF_SIZE:
- if (comp == null)
- return 0;
- return isHor ? comp.getPreferredWidth() : comp.getPreferredHeight();
-
- case MAX_SIZE:
- if (comp == null)
- return 0;
- return isHor ? comp.getMaximumWidth() : comp.getMaximumHeight();
-
- case BUTTON:
- return PlatformDefaults.getMinimumButtonWidth().getPixels(refValue, parent, comp);
-
- case LINK_X:
- case LINK_Y:
- case LINK_W:
- case LINK_H:
- case LINK_X2:
- case LINK_Y2:
- case LINK_XPOS:
- case LINK_YPOS:
- Integer v = LinkHandler.getValue(parent.getLayout(), getLinkTargetId(), unit - (unit >= LINK_XPOS ? LINK_XPOS : LINK_X));
- if (v == null)
- return 0;
-
- if (unit == LINK_XPOS)
- return parent.getScreenLocationX() + v.intValue();
- if (unit == LINK_YPOS)
- return parent.getScreenLocationY() + v.intValue();
-
- return v.intValue();
-
- case LOOKUP:
- float res = lookup(refValue, parent, comp);
- if (res != UnitConverter.UNABLE)
- return res;
-
- case LABEL_ALIGN:
- return PlatformDefaults.getLabelAlignPercentage() * refValue;
-
- case IDENTITY:
- }
- throw new IllegalArgumentException("Unknown/illegal unit: " + unit + ", unitStr: " + unitStr);
- }
-
- if (subUnits != null && subUnits.length == 2) {
- float r1 = subUnits[0].getPixelsExact(refValue, parent, comp);
- float r2 = subUnits[1].getPixelsExact(refValue, parent, comp);
- switch (oper) {
- case ADD:
- return r1 + r2;
- case SUB:
- return r1 - r2;
- case MUL:
- return r1 * r2;
- case DIV:
- return r1 / r2;
- case MIN:
- return r1 < r2 ? r1 : r2;
- case MAX:
- return r1 > r2 ? r1 : r2;
- case MID:
- return (r1 + r2) * 0.5f;
- }
- }
-
- throw new IllegalArgumentException("Internal: Unknown Oper: " + oper);
- }
-
- private final float lookup(float refValue, ContainerWrapper parent, ComponentWrapper comp)
- {
- float res = UnitConverter.UNABLE;
- for (int i = CONVERTERS.size() - 1; i >= 0; i--) {
- res = CONVERTERS.get(i).convertToPixels(value, unitStr, isHor, refValue, parent, comp);
- if (res != UnitConverter.UNABLE)
- return res;
- }
- return PlatformDefaults.convertToPixels(value, unitStr, isHor, refValue, parent, comp);
- }
-
- private final int parseUnitString()
- {
- int len = unitStr.length();
- if (len == 0)
- return isHor ? PlatformDefaults.getDefaultHorizontalUnit() : PlatformDefaults.getDefaultVerticalUnit();
-
- Integer u = UNIT_MAP.get(unitStr);
- if (u != null)
- return u.intValue();
-
- if (unitStr.equals("lp"))
- return isHor ? LPX : LPY;
-
- if (unitStr.equals("sp"))
- return isHor ? SPX : SPY;
-
- if (lookup(0, null, null) != UnitConverter.UNABLE) // To test so we can fail fast
- return LOOKUP;
-
- if (unitStr.endsWith(".x"))
- return LINK_X;
- if (unitStr.endsWith(".y"))
- return LINK_Y;
- if (unitStr.endsWith(".w") || unitStr.endsWith(".width"))
- return LINK_W;
- if (unitStr.endsWith(".h") || unitStr.endsWith(".height"))
- return LINK_H;
- if (unitStr.endsWith(".x2"))
- return LINK_X2;
- if (unitStr.endsWith(".y2"))
- return LINK_Y2;
- if (unitStr.endsWith(".xpos"))
- return LINK_XPOS;
- if (unitStr.endsWith(".ypos"))
- return LINK_YPOS;
-
- throw new IllegalArgumentException("Unknown keyword: " + unitStr);
- }
-
- final boolean isLinked()
- {
- return unit >= LINK_X && unit <= LINK_YPOS;
- }
-
- final boolean isLinkedDeep()
- {
- if (subUnits == null)
- return isLinked();
-
- for (int i = 0; i < subUnits.length; i++) {
- if (subUnits[i].isLinkedDeep())
- return true;
- }
-
- return false;
- }
-
- final String getLinkTargetId()
- {
- return unitStr.substring(0, unitStr.length() - (unit < LINK_X2 ? 2 : (unit > LINK_Y2 ? 5 : 3)));
- }
-
- final UnitValue getSubUnitValue(int i)
- {
- return subUnits[i];
- }
-
- final int getSubUnitCount()
- {
- return subUnits != null ? subUnits.length : 0;
- }
-
- public final UnitValue[] getSubUnits()
- {
- return subUnits;
- }
-
- public final int getUnit()
- {
- return unit;
- }
-
- public final String getUnitString()
- {
- return unitStr;
- }
-
- public final int getOperation()
- {
- return oper;
- }
-
- public final float getValue()
- {
- return value;
- }
-
- public final boolean isHorizontal()
- {
- return isHor;
- }
-
- final public String toString()
- {
- return getClass().getName() + ". Value=" + value + ", unit=" + unit + ", unitString: " + unitStr + ", oper=" + oper + ", isHor: " + isHor;
- }
-
- /** Returns the creation string for this object. Note that {@link LayoutUtil#setDesignTime(ContainerWrapper, boolean)} must be
- * set to <code>true</code> for the creation strings to be stored.
- * @return The constraint string or <code>null</code> if none is registered.
- */
- public final String getConstraintString()
- {
- return LayoutUtil.getCCString(this);
- }
-
- public final int hashCode()
- {
- return (int) (value * 12345) + (oper >>> 5) + unit >>> 17;
- }
-
- /** Adds a global unit converter that can convert from some <code>unit</code> to pixels.
- * <p>
- * This converter will be asked before the platform converter so the values for it (e.g. "related" and "unrelated")
- * can be overridden. It is however not possible to override the built in ones (e.g. "mm", "pixel" or "lp").
- * @param conv The converter. Not <code>null</code>.
- */
- public final synchronized static void addGlobalUnitConverter(UnitConverter conv)
- {
- if (conv == null)
- throw new NullPointerException();
- CONVERTERS.add(conv);
- }
-
- /** Removed the converter.
- * @param unit The converter.
- * @return If there was a converter found and thus removed.
- */
- public final synchronized static boolean removeGlobalUnitConverter(String unit)
- {
- return CONVERTERS.remove(unit);
- }
-
- /** Returns the global converters currently registered. The platform converter will not be in this list.
- * @return The converters. Never <code>null</code>.
- */
- public final synchronized static UnitConverter[] getGlobalUnitConverters()
- {
- return CONVERTERS.toArray(new UnitConverter[CONVERTERS.size()]);
- }
-
- /** Returns the current default unit. The default unit is the unit used if no unit is set. E.g. "width 10".
- * @return The current default unit.
- * @see #PIXEL
- * @see #LPX
- * @deprecated Use {@link PlatformDefaults#getDefaultHorizontalUnit()} and {@link PlatformDefaults#getDefaultVerticalUnit()} instead.
- */
- public final static int getDefaultUnit()
- {
- return PlatformDefaults.getDefaultHorizontalUnit();
- }
-
- /** Sets the default unit. The default unit is the unit used if no unit is set. E.g. "width 10".
- * @param unit The new default unit.
- * @see #PIXEL
- * @see #LPX
- * @deprecated Use {@link PlatformDefaults#setDefaultHorizontalUnit(int)} and {@link PlatformDefaults#setDefaultVerticalUnit(int)} instead.
- */
- public final static void setDefaultUnit(int unit)
- {
- PlatformDefaults.setDefaultHorizontalUnit(unit);
- PlatformDefaults.setDefaultVerticalUnit(unit);
- }
-
- static {
- LayoutUtil.setDelegate(UnitValue.class, new PersistenceDelegate() {
- protected Expression instantiate(Object oldInstance, Encoder out)
- {
- UnitValue uv = (UnitValue) oldInstance;
- String cs = uv.getConstraintString();
- if (cs == null)
- throw new IllegalStateException("Design time must be on to use XML persistence. See LayoutUtil.");
-
- return new Expression(oldInstance, ConstraintParser.class, "parseUnitValueOrAlign", new Object[] {
- uv.getConstraintString(), (uv.isHorizontal() ? Boolean.TRUE : Boolean.FALSE), null
- });
- }
- });
- }
-
- // ************************************************
- // Persistence Delegate and Serializable combined.
- // ************************************************
-
- private static final long serialVersionUID = 1L;
-
- private Object readResolve() throws ObjectStreamException
- {
- return LayoutUtil.getSerializedObject(this);
- }
-
- private void writeObject(ObjectOutputStream out) throws IOException
- {
- if (getClass() == UnitValue.class)
- LayoutUtil.writeAsXML(out, this);
- }
-
- private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException
- {
- LayoutUtil.setSerializedObject(this, LayoutUtil.readAsXML(in));
- }
+package net.miginfocom.layout; +/* + * License (BSD): + * ============== + * + * Copyright (c) 2004, Mikael Grev, MiG InfoCom AB. (miglayout (at) miginfocom (dot) com) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright notice, this list + * of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * Neither the name of the MiG InfoCom AB nor the names of its contributors may be + * used to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * @version 1.0 + * @author Mikael Grev, MiG InfoCom AB + * Date: 2006-sep-08 + */ + +import java.beans.Encoder; +import java.beans.Expression; +import java.beans.PersistenceDelegate; +import java.io.*; +import java.util.ArrayList; +import java.util.HashMap; + +public final class UnitValue implements Serializable +{ + private static final HashMap<String, Integer> UNIT_MAP = new HashMap<String, Integer>(32); + + private static final ArrayList<UnitConverter> CONVERTERS = new ArrayList<UnitConverter>(); + + /** An operation indicating a static value. + */ + public static final int STATIC = 100; + + /** An operation indicating a addition of two sub units. + */ + public static final int ADD = 101; // Must have "sub-unit values" + + /** An operation indicating a subtraction of two sub units + */ + public static final int SUB = 102; // Must have "sub-unit values" + + /** An operation indicating a multiplication of two sub units. + */ + public static final int MUL = 103; // Must have "sub-unit values" + + /** An operation indicating a division of two sub units. + */ + public static final int DIV = 104; // Must have "sub-unit values" + + /** An operation indicating the minimum of two sub units + */ + public static final int MIN = 105; // Must have "sub-unit values" + + /** An operation indicating the maximum of two sub units + */ + public static final int MAX = 106; // Must have "sub-unit values" + + /** An operation indicating the middle value of two sub units + */ + public static final int MID = 107; // Must have "sub-unit values" + + + + + /** A unit indicating pixels. + */ + public static final int PIXEL = 0; + + /** A unit indicating logical horizontal pixels. + */ + public static final int LPX = 1; + + /** A unit indicating logical vertical pixels. + */ + public static final int LPY = 2; + + /** A unit indicating millimeters. + */ + public static final int MM = 3; + + /** A unit indicating centimeters. + */ + public static final int CM = 4; + + /** A unit indicating inches. + */ + public static final int INCH = 5; + + /** A unit indicating percent. + */ + public static final int PERCENT = 6; + + /** A unit indicating points. + */ + public static final int PT = 7; + + /** A unit indicating screen width in pixels. + */ + public static final int SPX = 8; + + /** A unit indicating screen height in pixels. + */ + public static final int SPY = 9; + + /** A unit indicating alignment. + */ + public static final int ALIGN = 12; + + /** A unit indicating minimum size. + */ + public static final int MIN_SIZE = 13; + + /** A unit indicating preferred size. + */ + public static final int PREF_SIZE = 14; + + /** A unit indicating maximum size. + */ + public static final int MAX_SIZE = 15; + + /** A unit indicating botton size. + */ + public static final int BUTTON = 16; + + /** A unit indicating linking to x. + */ + public static final int LINK_X = 18; // First link + + /** A unit indicating linking to y. + */ + public static final int LINK_Y = 19; + + /** A unit indicating linking to width. + */ + public static final int LINK_W = 20; + + /** A unit indicating linking to height. + */ + public static final int LINK_H = 21; + + /** A unit indicating linking to x2. + */ + public static final int LINK_X2 = 22; + + /** A unit indicating linking to y2. + */ + public static final int LINK_Y2 = 23; + + /** A unit indicating linking to x position on screen. + */ + public static final int LINK_XPOS = 24; + + /** A unit indicating linking to y position on screen. + */ + public static final int LINK_YPOS = 25; // Last link + + /** A unit indicating a lookup. + */ + public static final int LOOKUP = 26; + + /** A unit indicating label alignment. + */ + public static final int LABEL_ALIGN = 27; + + private static final int IDENTITY = -1; + + static { + UNIT_MAP.put("px", new Integer(PIXEL)); + UNIT_MAP.put("lpx", new Integer(LPX)); + UNIT_MAP.put("lpy", new Integer(LPY)); + UNIT_MAP.put("%", new Integer(PERCENT)); + UNIT_MAP.put("cm", new Integer(CM)); + UNIT_MAP.put("in", new Integer(INCH)); + UNIT_MAP.put("spx", new Integer(SPX)); + UNIT_MAP.put("spy", new Integer(SPY)); + UNIT_MAP.put("al", new Integer(ALIGN)); + UNIT_MAP.put("mm", new Integer(MM)); + UNIT_MAP.put("pt", new Integer(PT)); + UNIT_MAP.put("min", new Integer(MIN_SIZE)); + UNIT_MAP.put("minimum", new Integer(MIN_SIZE)); + UNIT_MAP.put("p", new Integer(PREF_SIZE)); + UNIT_MAP.put("pref", new Integer(PREF_SIZE)); + UNIT_MAP.put("max", new Integer(MAX_SIZE)); + UNIT_MAP.put("maximum", new Integer(MAX_SIZE)); + UNIT_MAP.put("button", new Integer(BUTTON)); + UNIT_MAP.put("label", new Integer(LABEL_ALIGN)); + } + + static final UnitValue ZERO = new UnitValue(0, null, PIXEL, true, STATIC, null, null, "0px"); + static final UnitValue TOP = new UnitValue(0, null, PERCENT, false, STATIC, null, null, "top"); + static final UnitValue LEADING = new UnitValue(0, null, PERCENT, true, STATIC, null, null, "leading"); + static final UnitValue LEFT = new UnitValue(0, null, PERCENT, true, STATIC, null, null, "left"); + static final UnitValue CENTER = new UnitValue(50, null, PERCENT, true, STATIC, null, null, "center"); + static final UnitValue TRAILING = new UnitValue(100, null, PERCENT, true, STATIC, null, null, "trailing"); + static final UnitValue RIGHT = new UnitValue(100, null, PERCENT, true, STATIC, null, null, "right"); + static final UnitValue BOTTOM = new UnitValue(100, null, PERCENT, false, STATIC, null, null, "bottom"); + static final UnitValue LABEL = new UnitValue(0, null, LABEL_ALIGN, false, STATIC, null, null, "label"); + + static final UnitValue INF = new UnitValue(LayoutUtil.INF, null, PIXEL, true, STATIC, null, null, "inf"); + + static final UnitValue BASELINE_IDENTITY = new UnitValue(0, null, IDENTITY, false, STATIC, null, null, "baseline"); + + private final transient float value; + private final transient int unit; + private final transient int oper; + private final transient String unitStr; + private final transient boolean isHor; + private final transient UnitValue[] subUnits; + + // Pixel + public UnitValue(float value) // If hor/ver does not matter. + { + this(value, null, PIXEL, true, STATIC, null, null, value + "px"); + } + + public UnitValue(float value, int unit, String createString) // If hor/ver does not matter. + { + this(value, null, unit, true, STATIC, null, null, createString); + } + + UnitValue(float value, String unitStr, boolean isHor, int oper, String createString) + { + this(value, unitStr, -1, isHor, oper, null, null, createString); + } + + UnitValue(boolean isHor, int oper, UnitValue sub1, UnitValue sub2, String createString) + { + this(0, "", -1, isHor, oper, sub1, sub2, createString); + if (sub1 == null || sub2 == null) + throw new IllegalArgumentException("Sub units is null!"); + } + + private UnitValue(float value, String unitStr, int unit, boolean isHor, int oper, UnitValue sub1, UnitValue sub2, String createString) + { + if (oper < STATIC || oper > MID) + throw new IllegalArgumentException("Unknown Operation: " + oper); + + if (oper >= ADD && oper <= MID && (sub1 == null || sub2 == null)) + throw new IllegalArgumentException(oper + " Operation may not have null sub-UnitValues."); + + this.value = value; + this.oper = oper; + this.isHor = isHor; + this.unitStr = unitStr; + this.unit = unitStr != null ? parseUnitString() : unit; + this.subUnits = sub1 != null && sub2 != null ? new UnitValue[] {sub1, sub2} : null; + + LayoutUtil.putCCString(this, createString); // "this" escapes!! Safe though. + } + + /** Returns the size in pixels rounded. + * @param refValue The reference value. Normally the size of the parent. For unit {@link #ALIGN} the current size of the component should be sent in. + * @param parent The parent. May be <code>null</code> for testing the validity of the value, but should normally not and are not + * required to return any usable value if <code>null</code>. + * @param comp The component, if any, that the value is for. Might be <code>null</code> if the value is not + * connected to any component. + * @return The size in pixels. + */ + public final int getPixels(float refValue, ContainerWrapper parent, ComponentWrapper comp) + { + return Math.round(getPixelsExact(refValue, parent, comp)); + } + + private static final float[] SCALE = new float[] {25.4f, 2.54f, 1f, 0f, 72f}; + /** Returns the size in pixels. + * @param refValue The reference value. Normally the size of the parent. For unit {@link #ALIGN} the current size of the component should be sent in. + * @param parent The parent. May be <code>null</code> for testing the validity of the value, but should normally not and are not + * required to return any usable value if <code>null</code>. + * @param comp The component, if any, that the value is for. Might be <code>null</code> if the value is not + * connected to any component. + * @return The size in pixels. + */ + public final float getPixelsExact(float refValue, ContainerWrapper parent, ComponentWrapper comp) + { + if (parent == null) + return 1; + + if (oper == STATIC) { + switch (unit) { + case PIXEL: + return value; + + case LPX: + case LPY: + return parent.getPixelUnitFactor(unit == LPX) * value; + + case MM: + case CM: + case INCH: + case PT: + float f = SCALE[unit - MM]; + Float s = isHor ? PlatformDefaults.getHorizontalScaleFactor() : PlatformDefaults.getVerticalScaleFactor(); + if (s != null) + f *= s.floatValue(); + return (isHor ? parent.getHorizontalScreenDPI() : parent.getVerticalScreenDPI()) * value / f; + + case PERCENT: + return value * refValue * 0.01f; + + case SPX: + case SPY: + return (unit == SPX ? parent.getScreenWidth() : parent.getScreenHeight()) * value * 0.01f; + + case ALIGN: + Integer st = LinkHandler.getValue(parent.getLayout(), "visual", isHor ? LinkHandler.X : LinkHandler.Y); + Integer sz = LinkHandler.getValue(parent.getLayout(), "visual", isHor ? LinkHandler.WIDTH : LinkHandler.HEIGHT); + if (st == null || sz == null) + return 0; + return value * (Math.max(0, sz.intValue()) - refValue) + st.intValue(); + + case MIN_SIZE: + if (comp == null) + return 0; + return isHor ? comp.getMinimumWidth() : comp.getMinimumHeight(); + + case PREF_SIZE: + if (comp == null) + return 0; + return isHor ? comp.getPreferredWidth() : comp.getPreferredHeight(); + + case MAX_SIZE: + if (comp == null) + return 0; + return isHor ? comp.getMaximumWidth() : comp.getMaximumHeight(); + + case BUTTON: + return PlatformDefaults.getMinimumButtonWidth().getPixels(refValue, parent, comp); + + case LINK_X: + case LINK_Y: + case LINK_W: + case LINK_H: + case LINK_X2: + case LINK_Y2: + case LINK_XPOS: + case LINK_YPOS: + Integer v = LinkHandler.getValue(parent.getLayout(), getLinkTargetId(), unit - (unit >= LINK_XPOS ? LINK_XPOS : LINK_X)); + if (v == null) + return 0; + + if (unit == LINK_XPOS) + return parent.getScreenLocationX() + v.intValue(); + if (unit == LINK_YPOS) + return parent.getScreenLocationY() + v.intValue(); + + return v.intValue(); + + case LOOKUP: + float res = lookup(refValue, parent, comp); + if (res != UnitConverter.UNABLE) + return res; + + case LABEL_ALIGN: + return PlatformDefaults.getLabelAlignPercentage() * refValue; + + case IDENTITY: + } + throw new IllegalArgumentException("Unknown/illegal unit: " + unit + ", unitStr: " + unitStr); + } + + if (subUnits != null && subUnits.length == 2) { + float r1 = subUnits[0].getPixelsExact(refValue, parent, comp); + float r2 = subUnits[1].getPixelsExact(refValue, parent, comp); + switch (oper) { + case ADD: + return r1 + r2; + case SUB: + return r1 - r2; + case MUL: + return r1 * r2; + case DIV: + return r1 / r2; + case MIN: + return r1 < r2 ? r1 : r2; + case MAX: + return r1 > r2 ? r1 : r2; + case MID: + return (r1 + r2) * 0.5f; + } + } + + throw new IllegalArgumentException("Internal: Unknown Oper: " + oper); + } + + private final float lookup(float refValue, ContainerWrapper parent, ComponentWrapper comp) + { + float res = UnitConverter.UNABLE; + for (int i = CONVERTERS.size() - 1; i >= 0; i--) { + res = CONVERTERS.get(i).convertToPixels(value, unitStr, isHor, refValue, parent, comp); + if (res != UnitConverter.UNABLE) + return res; + } + return PlatformDefaults.convertToPixels(value, unitStr, isHor, refValue, parent, comp); + } + + private final int parseUnitString() + { + int len = unitStr.length(); + if (len == 0) + return isHor ? PlatformDefaults.getDefaultHorizontalUnit() : PlatformDefaults.getDefaultVerticalUnit(); + + Integer u = UNIT_MAP.get(unitStr); + if (u != null) + return u.intValue(); + + if (unitStr.equals("lp")) + return isHor ? LPX : LPY; + + if (unitStr.equals("sp")) + return isHor ? SPX : SPY; + + if (lookup(0, null, null) != UnitConverter.UNABLE) // To test so we can fail fast + return LOOKUP; + + if (unitStr.endsWith(".x")) + return LINK_X; + if (unitStr.endsWith(".y")) + return LINK_Y; + if (unitStr.endsWith(".w") || unitStr.endsWith(".width")) + return LINK_W; + if (unitStr.endsWith(".h") || unitStr.endsWith(".height")) + return LINK_H; + if (unitStr.endsWith(".x2")) + return LINK_X2; + if (unitStr.endsWith(".y2")) + return LINK_Y2; + if (unitStr.endsWith(".xpos")) + return LINK_XPOS; + if (unitStr.endsWith(".ypos")) + return LINK_YPOS; + + throw new IllegalArgumentException("Unknown keyword: " + unitStr); + } + + final boolean isLinked() + { + return unit >= LINK_X && unit <= LINK_YPOS; + } + + final boolean isLinkedDeep() + { + if (subUnits == null) + return isLinked(); + + for (int i = 0; i < subUnits.length; i++) { + if (subUnits[i].isLinkedDeep()) + return true; + } + + return false; + } + + final String getLinkTargetId() + { + return unitStr.substring(0, unitStr.length() - (unit < LINK_X2 ? 2 : (unit > LINK_Y2 ? 5 : 3))); + } + + final UnitValue getSubUnitValue(int i) + { + return subUnits[i]; + } + + final int getSubUnitCount() + { + return subUnits != null ? subUnits.length : 0; + } + + public final UnitValue[] getSubUnits() + { + return subUnits; + } + + public final int getUnit() + { + return unit; + } + + public final String getUnitString() + { + return unitStr; + } + + public final int getOperation() + { + return oper; + } + + public final float getValue() + { + return value; + } + + public final boolean isHorizontal() + { + return isHor; + } + + final public String toString() + { + return getClass().getName() + ". Value=" + value + ", unit=" + unit + ", unitString: " + unitStr + ", oper=" + oper + ", isHor: " + isHor; + } + + /** Returns the creation string for this object. Note that {@link LayoutUtil#setDesignTime(ContainerWrapper, boolean)} must be + * set to <code>true</code> for the creation strings to be stored. + * @return The constraint string or <code>null</code> if none is registered. + */ + public final String getConstraintString() + { + return LayoutUtil.getCCString(this); + } + + public final int hashCode() + { + return (int) (value * 12345) + (oper >>> 5) + unit >>> 17; + } + + /** Adds a global unit converter that can convert from some <code>unit</code> to pixels. + * <p> + * This converter will be asked before the platform converter so the values for it (e.g. "related" and "unrelated") + * can be overridden. It is however not possible to override the built in ones (e.g. "mm", "pixel" or "lp"). + * @param conv The converter. Not <code>null</code>. + */ + public final synchronized static void addGlobalUnitConverter(UnitConverter conv) + { + if (conv == null) + throw new NullPointerException(); + CONVERTERS.add(conv); + } + + /** Removed the converter. + * @param unit The converter. + * @return If there was a converter found and thus removed. + */ + public final synchronized static boolean removeGlobalUnitConverter(String unit) + { + return CONVERTERS.remove(unit); + } + + /** Returns the global converters currently registered. The platform converter will not be in this list. + * @return The converters. Never <code>null</code>. + */ + public final synchronized static UnitConverter[] getGlobalUnitConverters() + { + return CONVERTERS.toArray(new UnitConverter[CONVERTERS.size()]); + } + + /** Returns the current default unit. The default unit is the unit used if no unit is set. E.g. "width 10". + * @return The current default unit. + * @see #PIXEL + * @see #LPX + * @deprecated Use {@link PlatformDefaults#getDefaultHorizontalUnit()} and {@link PlatformDefaults#getDefaultVerticalUnit()} instead. + */ + public final static int getDefaultUnit() + { + return PlatformDefaults.getDefaultHorizontalUnit(); + } + + /** Sets the default unit. The default unit is the unit used if no unit is set. E.g. "width 10". + * @param unit The new default unit. + * @see #PIXEL + * @see #LPX + * @deprecated Use {@link PlatformDefaults#setDefaultHorizontalUnit(int)} and {@link PlatformDefaults#setDefaultVerticalUnit(int)} instead. + */ + public final static void setDefaultUnit(int unit) + { + PlatformDefaults.setDefaultHorizontalUnit(unit); + PlatformDefaults.setDefaultVerticalUnit(unit); + } + + static { + LayoutUtil.setDelegate(UnitValue.class, new PersistenceDelegate() { + protected Expression instantiate(Object oldInstance, Encoder out) + { + UnitValue uv = (UnitValue) oldInstance; + String cs = uv.getConstraintString(); + if (cs == null) + throw new IllegalStateException("Design time must be on to use XML persistence. See LayoutUtil."); + + return new Expression(oldInstance, ConstraintParser.class, "parseUnitValueOrAlign", new Object[] { + uv.getConstraintString(), (uv.isHorizontal() ? Boolean.TRUE : Boolean.FALSE), null + }); + } + }); + } + + // ************************************************ + // Persistence Delegate and Serializable combined. + // ************************************************ + + private static final long serialVersionUID = 1L; + + private Object readResolve() throws ObjectStreamException + { + return LayoutUtil.getSerializedObject(this); + } + + private void writeObject(ObjectOutputStream out) throws IOException + { + if (getClass() == UnitValue.class) + LayoutUtil.writeAsXML(out, this); + } + + private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException + { + LayoutUtil.setSerializedObject(this, LayoutUtil.readAsXML(in)); + } }
\ No newline at end of file |