summaryrefslogtreecommitdiff
path: root/prototypes/miglayout/net/miginfocom/layout
diff options
context:
space:
mode:
authorGraeme Geldenhuys <graeme@mastermaths.co.za>2012-11-22 11:48:47 +0000
committerGraeme Geldenhuys <graeme@mastermaths.co.za>2012-11-22 11:48:47 +0000
commitaf45f95f16cee22f8f012f706f4d0a42eaeb68fa (patch)
treec572c1cc6a7d3bb12874d8f9b9363312b275e328 /prototypes/miglayout/net/miginfocom/layout
parent9c62dfaf7217557f08a3d33b20bb302874960f87 (diff)
downloadfpGUI-af45f95f16cee22f8f012f706f4d0a42eaeb68fa.tar.xz
Fixes line ending issues
Diffstat (limited to 'prototypes/miglayout/net/miginfocom/layout')
-rw-r--r--prototypes/miglayout/net/miginfocom/layout/AC.java984
-rw-r--r--prototypes/miglayout/net/miginfocom/layout/BoundSize.java490
-rw-r--r--prototypes/miglayout/net/miginfocom/layout/CC.java3084
-rw-r--r--prototypes/miglayout/net/miginfocom/layout/ComponentWrapper.java514
-rw-r--r--prototypes/miglayout/net/miginfocom/layout/ConstraintParser.java2818
-rw-r--r--prototypes/miglayout/net/miginfocom/layout/ContainerWrapper.java138
-rw-r--r--prototypes/miglayout/net/miginfocom/layout/DimConstraint.java932
-rw-r--r--prototypes/miglayout/net/miginfocom/layout/Grid.java4490
-rw-r--r--prototypes/miglayout/net/miginfocom/layout/IDEUtil.java1408
-rw-r--r--prototypes/miglayout/net/miginfocom/layout/InCellGapProvider.java62
-rw-r--r--prototypes/miglayout/net/miginfocom/layout/LC.java1434
-rw-r--r--prototypes/miglayout/net/miginfocom/layout/LayoutCallback.java96
-rw-r--r--prototypes/miglayout/net/miginfocom/layout/LayoutUtil.java1064
-rw-r--r--prototypes/miglayout/net/miginfocom/layout/LinkHandler.java364
-rw-r--r--prototypes/miglayout/net/miginfocom/layout/PlatformDefaults.java1348
-rw-r--r--prototypes/miglayout/net/miginfocom/layout/ResizeConstraint.java184
-rw-r--r--prototypes/miglayout/net/miginfocom/layout/UnitConverter.java118
-rw-r--r--prototypes/miglayout/net/miginfocom/layout/UnitValue.java1250
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 &gt;= 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 &gt;= 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 &gt;= 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 &gt;= 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 &gt; 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 &gt; 0 OR unspecified.
- * <li>2 - Grow all rows/columns that has a grow weight &gt; 0.
- * <li>3 - Grow all rows/columns that has a grow weight &gt; 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 &gt; 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 &gt; 0 OR unspecified.
+ * <li>2 - Grow all rows/columns that has a grow weight &gt; 0.
+ * <li>3 - Grow all rows/columns that has a grow weight &gt; 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>&gt; 0</code> the debug decorations will be repainted every <code>millis</code>. No debug information if <code>&lt;= 0</code> (default).
- * @return The current debug repaint interval.
- */
- public final int getDebugMillis()
- {
- return debugMillis;
- }
-
- /** If <code>&gt; 0</code> the debug decorations will be repainted every <code>millis</code>. No debug information if <code>&lt;= 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>&gt; 0</code> the debug decorations will be repainted every <code>millis</code>. No debug information if <code>&lt;= 0</code> (default).
+ * @return The current debug repaint interval.
+ */
+ public final int getDebugMillis()
+ {
+ return debugMillis;
+ }
+
+ /** If <code>&gt; 0</code> the debug decorations will be repainted every <code>millis</code>. No debug information if <code>&lt;= 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 &lt; 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 &lt; 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