Coverage Report - net.miginfocom.layout.ConstraintParser
 
Classes in this File Line Coverage Branch Coverage Complexity
ConstraintParser
N/A
N/A
19.292
 
 1  
 package net.miginfocom.layout;
 2  
 
 3  
 import java.util.ArrayList;
 4  
 import java.util.HashMap;
 5  
 import java.util.Iterator;
 6  
 import java.util.Map;
 7  
 /*
 8  
  * License (BSD):
 9  
  * ==============
 10  
  *
 11  
  * Copyright (c) 2004, Mikael Grev, MiG InfoCom AB. (miglayout (at) miginfocom (dot) com)
 12  
  * All rights reserved.
 13  
  *
 14  
  * Redistribution and use in source and binary forms, with or without modification,
 15  
  * are permitted provided that the following conditions are met:
 16  
  * Redistributions of source code must retain the above copyright notice, this list
 17  
  * of conditions and the following disclaimer.
 18  
  * Redistributions in binary form must reproduce the above copyright notice, this
 19  
  * list of conditions and the following disclaimer in the documentation and/or other
 20  
  * materials provided with the distribution.
 21  
  * Neither the name of the MiG InfoCom AB nor the names of its contributors may be
 22  
  * used to endorse or promote products derived from this software without specific
 23  
  * prior written permission.
 24  
  *
 25  
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 26  
  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 27  
  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 28  
  * IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
 29  
  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 30  
  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
 31  
  * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 32  
  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 33  
  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
 34  
  * OF SUCH DAMAGE.
 35  
  *
 36  
  * @version 1.0
 37  
  * @author Mikael Grev, MiG InfoCom AB
 38  
  *         Date: 2006-sep-08
 39  
  */
 40  
 
 41  
 /** Parses string constraints.
 42  
  */
 43  
 public final class ConstraintParser
 44  
 {
 45  
         private ConstraintParser()
 46  
         {
 47  
         }
 48  
 
 49  
         /** Parses the layout constraints and stores the parsed values in the transient (cache) member varables.
 50  
          * @param s The String to parse. Should not be <code>null</code> and <b>must be lower case and trimmed</b>.
 51  
          * @throws RuntimeException if the constaint was not valid.
 52  
          * @return The parsed constraint. Never <code>null</code>.
 53  
          */
 54  
         public static LC parseLayoutConstraint(String s)
 55  
         {
 56  
                 LC lc = new LC();
 57  
                 if (s.length() == 0)
 58  
                         return lc;
 59  
 
 60  
                 String[] parts = toTrimmedTokens(s, ',');
 61  
 
 62  
                 // First check for "ltr" or "rtl" since that will affect the interpretation of the other constraints.
 63  
                 for (int i = 0; i < parts.length; i++) {
 64  
                         String part = parts[i];
 65  
                         if (part == null)
 66  
                                 continue;
 67  
 
 68  
                         int len = part.length();
 69  
                         if (len == 3 || len == 11) {   // Optimization
 70  
                                 if (part.equals("ltr") || part.equals("rtl") || part.equals("lefttoright") || part.equals("righttoleft")) {
 71  
                                         lc.setLeftToRight(part.charAt(0) == 'l' ? Boolean.TRUE : Boolean.FALSE);
 72  
                                         parts[i] = null;    // So we will not try to interpret it again
 73  
                                 }
 74  
 
 75  
                                 if (part.equals("ttb") || part.equals("btt") || part.equals("toptobottom") || part.equals("bottomtotop")) {
 76  
                                         lc.setTopToBottom(part.charAt(0) == 't');
 77  
                                         parts[i] = null;    // So we will not try to interpret it again
 78  
                                 }
 79  
                         }
 80  
                 }
 81  
 
 82  
                 for (String part : parts) {
 83  
                         if (part == null || part.length() == 0)
 84  
                                 continue;
 85  
 
 86  
                         try {
 87  
                                 int ix = -1;
 88  
                                 char c = part.charAt(0);
 89  
 
 90  
                                 if (c == 'w' || c == 'h') {
 91  
 
 92  
                                         ix = startsWithLenient(part, "wrap", -1, true);
 93  
                                         if (ix > -1) {
 94  
                                                 String num = part.substring(ix).trim();
 95  
                                                 lc.setWrapAfter(num.length() != 0 ? Integer.parseInt(num) : 0);
 96  
                                                 continue;
 97  
                                         }
 98  
 
 99  
                                         boolean isHor = c == 'w';
 100  
                                         if (isHor && (part.startsWith("w ") || part.startsWith("width "))) {
 101  
                                                 String sz = part.substring(part.charAt(1) == ' ' ? 2 : 6).trim();
 102  
                                                 lc.setWidth(parseBoundSize(sz, false, true));
 103  
                                                 continue;
 104  
                                         }
 105  
 
 106  
                                         if (!isHor && (part.startsWith("h ") || part.startsWith("height "))) {
 107  
                                                 String uvStr = part.substring(part.charAt(1) == ' ' ? 2 : 7).trim();
 108  
                                                 lc.setHeight(parseBoundSize(uvStr, false, false));
 109  
                                                 continue;
 110  
                                         }
 111  
 
 112  
                                         if (part.length() > 5) {
 113  
                                                 String sz = part.substring(5).trim();
 114  
                                                 if (part.startsWith("wmin ")) {
 115  
                                                         lc.minWidth(sz);
 116  
                                                         continue;
 117  
                                                 } else if (part.startsWith("wmax ")) {
 118  
                                                         lc.maxWidth(sz);
 119  
                                                         continue;
 120  
                                                 } else if (part.startsWith("hmin ")) {
 121  
                                                         lc.minHeight(sz);
 122  
                                                         continue;
 123  
                                                 } else if (part.startsWith("hmax ")) {
 124  
                                                         lc.maxHeight(sz);
 125  
                                                         continue;
 126  
                                                 }
 127  
                                         }
 128  
 
 129  
                                         if (part.startsWith("hidemode ")) {
 130  
                                                 lc.setHideMode(Integer.parseInt(part.substring(9)));
 131  
                                                 continue;
 132  
                                         }
 133  
                                 }
 134  
 
 135  
                                 if (c == 'g') {
 136  
                                         if (part.startsWith("gapx ")) {
 137  
                                                 lc.setGridGapX(parseBoundSize(part.substring(5).trim(), true, true));
 138  
                                                 continue;
 139  
                                         }
 140  
 
 141  
                                         if (part.startsWith("gapy ")) {
 142  
                                                 lc.setGridGapY(parseBoundSize(part.substring(5).trim(), true, false));
 143  
                                                 continue;
 144  
                                         }
 145  
 
 146  
                                         if (part.startsWith("gap ")) {
 147  
                                                 String[] gaps = toTrimmedTokens(part.substring(4).trim(), ' ');
 148  
                                                 lc.setGridGapX(parseBoundSize(gaps[0], true, true));
 149  
                                                 lc.setGridGapY(gaps.length > 1 ? parseBoundSize(gaps[1], true, false) : lc.getGridGapX());
 150  
                                                 continue;
 151  
                                         }
 152  
                                 }
 153  
 
 154  
                                 if (c == 'd') {
 155  
                                         ix = startsWithLenient(part, "debug", 5, true);
 156  
                                         if (ix > -1) {
 157  
                                                 String millis = part.substring(ix).trim();
 158  
                                                 lc.setDebugMillis(millis.length() > 0 ? Integer.parseInt(millis) : 1000);
 159  
                                                 continue;
 160  
                                         }
 161  
                                 }
 162  
 
 163  
                                 if (c == 'n') {
 164  
                                         if (part.equals("nogrid")) {
 165  
                                                 lc.setNoGrid(true);
 166  
                                                 continue;
 167  
                                         }
 168  
 
 169  
                                         if (part.equals("nocache")) {
 170  
                                                 lc.setNoCache(true);
 171  
                                                 continue;
 172  
                                         }
 173  
 
 174  
                                         if (part.equals("novisualpadding")) {
 175  
                                                 lc.setVisualPadding(false);
 176  
                                                 continue;
 177  
                                         }
 178  
                                 }
 179  
 
 180  
                                 if (c == 'f') {
 181  
                                         if (part.equals("fill") || part.equals("fillx") || part.equals("filly")) {
 182  
                                                 lc.setFillX(part.length() == 4 || part.charAt(4) == 'x');
 183  
                                                 lc.setFillY(part.length() == 4 || part.charAt(4) == 'y');
 184  
                                                 continue;
 185  
                                         }
 186  
 
 187  
                                         if (part.equals("flowy")) {
 188  
                                                 lc.setFlowX(false);
 189  
                                                 continue;
 190  
                                         }
 191  
 
 192  
                                         if (part.equals("flowx")) {
 193  
                                                 lc.setFlowX(true); // This is the default but added for consistency
 194  
                                                 continue;
 195  
                                         }
 196  
                                 }
 197  
 
 198  
                                 if (c == 'i') {
 199  
                                         ix = startsWithLenient(part, "insets", 3, true);
 200  
                                         if (ix > -1) {
 201  
                                                 String insStr = part.substring(ix).trim();
 202  
                                                 UnitValue[] ins = parseInsets(insStr, true);
 203  
                                                 LayoutUtil.putCCString(ins, insStr);
 204  
                                                 lc.setInsets(ins);
 205  
                                                 continue;
 206  
                                         }
 207  
                                 }
 208  
 
 209  
                                 if (c == 'a') {
 210  
                                         ix = startsWithLenient(part, new String[]{"aligny", "ay"}, new int[]{6, 2}, true);
 211  
                                         if (ix > -1) {
 212  
                                                 UnitValue align = parseUnitValueOrAlign(part.substring(ix).trim(), false, null);
 213  
                                                 if (align == UnitValue.BASELINE_IDENTITY)
 214  
                                                         throw new IllegalArgumentException("'baseline' can not be used to align the whole component group.");
 215  
                                                 lc.setAlignY(align);
 216  
                                                 continue;
 217  
                                         }
 218  
 
 219  
                                         ix = startsWithLenient(part, new String[]{"alignx", "ax"}, new int[]{6, 2}, true);
 220  
                                         if (ix > -1) {
 221  
                                                 lc.setAlignX(parseUnitValueOrAlign(part.substring(ix).trim(), true, null));
 222  
                                                 continue;
 223  
                                         }
 224  
 
 225  
                                         ix = startsWithLenient(part, "align", 2, true);
 226  
                                         if (ix > -1) {
 227  
                                                 String[] gaps = toTrimmedTokens(part.substring(ix).trim(), ' ');
 228  
                                                 lc.setAlignX(parseUnitValueOrAlign(gaps[0], true, null));
 229  
                                                 if (gaps.length > 1)
 230  
                                                         lc.setAlignY(parseUnitValueOrAlign(gaps[1], false, null));
 231  
                                                 continue;
 232  
                                         }
 233  
                                 }
 234  
 
 235  
                                 if (c == 'p') {
 236  
                                         if (part.startsWith("packalign ")) {
 237  
                                                 String[] packs = toTrimmedTokens(part.substring(10).trim(), ' ');
 238  
                                                 lc.setPackWidthAlign(packs[0].length() > 0 ? Float.parseFloat(packs[0]) : 0.5f);
 239  
                                                 if (packs.length > 1)
 240  
                                                         lc.setPackHeightAlign(Float.parseFloat(packs[1]));
 241  
                                                 continue;
 242  
                                         }
 243  
 
 244  
                                         if (part.startsWith("pack ") || part.equals("pack")) {
 245  
                                                 String ps = part.substring(4).trim();
 246  
                                                 String[] packs = toTrimmedTokens(ps.length() > 0 ? ps : "pref pref", ' ');
 247  
                                                 lc.setPackWidth(parseBoundSize(packs[0], false, true));
 248  
                                                 if (packs.length > 1)
 249  
                                                         lc.setPackHeight(parseBoundSize(packs[1], false, false));
 250  
 
 251  
                                                 continue;
 252  
                                         }
 253  
                                 }
 254  
 
 255  
                                 if (lc.getAlignX() == null) {
 256  
                                         UnitValue alignX = parseAlignKeywords(part, true);
 257  
                                         if (alignX != null) {
 258  
                                                 lc.setAlignX(alignX);
 259  
                                                 continue;
 260  
                                         }
 261  
                                 }
 262  
 
 263  
                                 UnitValue alignY = parseAlignKeywords(part, false);
 264  
                                 if (alignY != null) {
 265  
                                         lc.setAlignY(alignY);
 266  
                                         continue;
 267  
                                 }
 268  
 
 269  
                                 throw new IllegalArgumentException("Unknown Constraint: '" + part + "'\n");
 270  
 
 271  
                         } catch (Exception ex) {
 272  
                                 throw new IllegalArgumentException("Illegal Constraint: '" + part + "'\n" + ex.getMessage());
 273  
                         }
 274  
                 }
 275  
 
 276  
 //                lc = (LC) serializeTest(lc);
 277  
 
 278  
                 return lc;
 279  
         }
 280  
 
 281  
         /** Parses the column or rows constraints. They normally looks something like <code>"[min:pref]rel[10px][]"</code>.
 282  
          * @param s The string to parse. Not <code>null</code>.
 283  
          * @return An array of {@link DimConstraint}s that is as many are there exist "[...]" sections in the string that is parsed.
 284  
          * @throws RuntimeException if the constraint was not valid.
 285  
          */
 286  
         public static AC parseRowConstraints(String s)
 287  
         {
 288  
                 return parseAxisConstraint(s, false);
 289  
         }
 290  
 
 291  
         /** Parses the column or rows constraints. They normally looks something like <code>"[min:pref]rel[10px][]"</code>.
 292  
          * @param s The string to parse. Not <code>null</code>.
 293  
          * @return An array of {@link DimConstraint}s that is as many are there exist "[...]" sections in the string that is parsed.
 294  
          * @throws RuntimeException if the constraint was not valid.
 295  
          */
 296  
         public static AC parseColumnConstraints(String s)
 297  
         {
 298  
                 return parseAxisConstraint(s, true);
 299  
         }
 300  
 
 301  
         /** Parses the column or rows constraints. They normally looks something like <code>"[min:pref]rel[10px][]"</code>.
 302  
          * @param s The string to parse. Not <code>null</code>.
 303  
          * @param isCols If this for columns rather than rows.
 304  
          * @return An array of {@link DimConstraint}s that is as many are there exist "[...]" sections in the string that is parsed.
 305  
          * @throws RuntimeException if the constraint was not valid.
 306  
          */
 307  
         private static AC parseAxisConstraint(String s, boolean isCols)
 308  
         {
 309  
                 s = s.trim();
 310  
 
 311  
                 if (s.length() == 0)
 312  
                         return new AC();    // Short circuit for performance.
 313  
 
 314  
                 s = s.toLowerCase();
 315  
 
 316  
                 ArrayList<String> parts = getRowColAndGapsTrimmed(s);
 317  
 
 318  
                 BoundSize[] gaps = new BoundSize[(parts.size() >> 1) + 1];
 319  
                 for (int i = 0, iSz = parts.size(), gIx = 0; i < iSz; i += 2, gIx++)
 320  
                         gaps[gIx] = parseBoundSize(parts.get(i), true, isCols);
 321  
 
 322  
                 DimConstraint[] colSpecs = new DimConstraint[parts.size() >> 1];
 323  
                 for (int i = 0, gIx = 0; i < colSpecs.length; i++, gIx++) {
 324  
                         if (gIx >= gaps.length - 1)
 325  
                                 gIx = gaps.length - 2;
 326  
 
 327  
                         colSpecs[i] = parseDimConstraint(parts.get((i << 1) + 1), gaps[gIx], gaps[gIx + 1], isCols);
 328  
                 }
 329  
 
 330  
                 AC ac = new AC();
 331  
                 ac.setConstaints(colSpecs);
 332  
 
 333  
 //                ac = (AC) serializeTest(ac);
 334  
 
 335  
                 return ac;
 336  
         }
 337  
 
 338  
         /** Parses a single column or row constraint.
 339  
          * @param s The single constraint to parse. May look something like <code>"min:pref,fill,grow"</code>. Should not be <code>null</code> and <b>must
 340  
          * be lower case and trimmed</b>.
 341  
          * @param gapBefore The default gap "before" the column/row constraint. Can be overridden with a <code>"gap"</code> section within <code>s</code>.
 342  
          * @param gapAfter The default gap "after" the column/row constraint. Can be overridden with a <code>"gap"</code> section within <code>s</code>.
 343  
          * @param isCols If the constraints are column constraints rather than row constraints.
 344  
          * @return A single constraint. Never <code>null</code>.
 345  
          * @throws RuntimeException if the constraint was not valid.
 346  
          */
 347  
         private static DimConstraint parseDimConstraint(String s, BoundSize gapBefore, BoundSize gapAfter, boolean isCols)
 348  
         {
 349  
                 DimConstraint dimConstraint = new DimConstraint();
 350  
 
 351  
                 // Default values.
 352  
                 dimConstraint.setGapBefore(gapBefore);
 353  
                 dimConstraint.setGapAfter(gapAfter);
 354  
 
 355  
                 String[] parts = toTrimmedTokens(s, ',');
 356  
                 for (int i = 0; i < parts.length; i++) {
 357  
                         String part = parts[i];
 358  
                         try {
 359  
                                 if (part.length() == 0)
 360  
                                         continue;
 361  
 
 362  
                                 if (part.equals("fill")) {
 363  
                                         dimConstraint.setFill(true);
 364  
 //                                         dimConstraint.setAlign(null);   // Can not have both fill and alignment (changed for 3.5 since it can have "growy 0")
 365  
                                         continue;
 366  
                                 }
 367  
 
 368  
                                 if (part.equals("nogrid")) {
 369  
                                         dimConstraint.setNoGrid(true);
 370  
                                         continue;
 371  
                                 }
 372  
 
 373  
                                 int ix = -1;
 374  
                                 char c = part.charAt(0);
 375  
 
 376  
                                 if (c == 's') {
 377  
                                         ix = startsWithLenient(part, new String[] {"sizegroup", "sg"}, new int[] {5, 2}, true);
 378  
                                         if (ix > -1) {
 379  
                                                 dimConstraint.setSizeGroup(part.substring(ix).trim());
 380  
                                                 continue;
 381  
                                         }
 382  
 
 383  
 
 384  
                                         ix = startsWithLenient(part, new String[] {"shrinkprio", "shp"}, new int[] {10, 3}, true);
 385  
                                         if (ix > -1) {
 386  
                                                 dimConstraint.setShrinkPriority(Integer.parseInt(part.substring(ix).trim()));
 387  
                                                 continue;
 388  
                                         }
 389  
 
 390  
                                         ix = startsWithLenient(part, "shrink", 6, true);
 391  
                                         if (ix > -1) {
 392  
                                                 dimConstraint.setShrink(parseFloat(part.substring(ix).trim(), ResizeConstraint.WEIGHT_100));
 393  
                                                 continue;
 394  
                                         }
 395  
                                 }
 396  
 
 397  
                                 if (c == 'g') {
 398  
                                         ix = startsWithLenient(part, new String[] {"growpriority", "gp"}, new int[] {5, 2}, true);
 399  
                                         if (ix > -1) {
 400  
                                                 dimConstraint.setGrowPriority(Integer.parseInt(part.substring(ix).trim()));
 401  
                                                 continue;
 402  
                                         }
 403  
 
 404  
                                         ix = startsWithLenient(part, "grow", 4, true);
 405  
                                         if (ix > -1) {
 406  
                                                 dimConstraint.setGrow(parseFloat(part.substring(ix).trim(), ResizeConstraint.WEIGHT_100));
 407  
                                                 continue;
 408  
                                         }
 409  
                                 }
 410  
 
 411  
                                 if (c == 'a') {
 412  
                                         ix = startsWithLenient(part, "align", 2, true);
 413  
                                         if (ix > -1) {
 414  
 //                                                if (dimConstraint.isFill() == false)    // Swallow, but ignore if fill is set. (changed for 3.5 since it can have "growy 0")
 415  
                                                         dimConstraint.setAlign(parseUnitValueOrAlign(part.substring(ix).trim(), isCols, null));
 416  
                                                 continue;
 417  
                                         }
 418  
                                 }
 419  
 
 420  
                                 UnitValue align = parseAlignKeywords(part, isCols);
 421  
                                 if (align != null) {
 422  
 //                                        if (dimConstraint.isFill() == false)    // Swallow, but ignore if fill is set. (changed for 3.5 since it can have "growy 0")
 423  
                                                 dimConstraint.setAlign(align);
 424  
                                         continue;
 425  
                                 }
 426  
 
 427  
                                  // Only min:pref:max still left that is ok
 428  
                                 dimConstraint.setSize(parseBoundSize(part, false, isCols));
 429  
 
 430  
                         } catch (Exception ex) {
 431  
                                 throw new IllegalArgumentException("Illegal contraint: '" + part + "'\n" + ex.getMessage());
 432  
                         }
 433  
                 }
 434  
                 return dimConstraint;
 435  
         }
 436  
 
 437  
         /** Parses all component constraints and stores the parsed values in the transient (cache) member varables.
 438  
          * @param constrMap The constraints as <code>String</code>s. Strings <b>must be lower case and trimmed</b>
 439  
          * @return The parsed constraints. Never <code>null</code>.
 440  
          */
 441  
         public static Map<ComponentWrapper, CC> parseComponentConstraints(Map<ComponentWrapper, String> constrMap)
 442  
         {
 443  
                 HashMap<ComponentWrapper, CC> flowConstrMap = new HashMap<ComponentWrapper, CC>();
 444  
 
 445  
                 for (Iterator<Map.Entry<ComponentWrapper, String>> it = constrMap.entrySet().iterator(); it.hasNext();) {
 446  
                         Map.Entry<ComponentWrapper, String> entry = it.next();
 447  
                         flowConstrMap.put(entry.getKey(), parseComponentConstraint(entry.getValue()));
 448  
                 }
 449  
 
 450  
                 return flowConstrMap;
 451  
         }
 452  
 
 453  
         /** Parses one component constraint and returns the parsed value.
 454  
          * @param s The string to parse. Should not be <code>null</code> and <b>must be lower case and trimmed</b>.
 455  
          * @throws RuntimeException if the constaint was not valid.
 456  
          * @return The parsed constraint. Never <code>null</code>.
 457  
          */
 458  
         public static CC parseComponentConstraint(String s)
 459  
         {
 460  
                 CC cc = new CC();
 461  
 
 462  
                 if (s.length() == 0)
 463  
                         return cc;
 464  
 
 465  
                 String[] parts = toTrimmedTokens(s, ',');
 466  
 
 467  
                 for (String part : parts) {
 468  
                         try {
 469  
                                 if (part.length() == 0)
 470  
                                         continue;
 471  
 
 472  
                                 int ix = -1;
 473  
                                 char c = part.charAt(0);
 474  
 
 475  
                                 if (c == 'n') {
 476  
                                         if (part.equals("north")) {
 477  
                                                 cc.setDockSide(0);
 478  
                                                 continue;
 479  
                                         }
 480  
 
 481  
                                         if (part.equals("newline")) {
 482  
                                                 cc.setNewline(true);
 483  
                                                 continue;
 484  
                                         }
 485  
 
 486  
                                         if (part.startsWith("newline ")) {
 487  
                                                 String gapSz = part.substring(7).trim();
 488  
                                                 cc.setNewlineGapSize(parseBoundSize(gapSz, true, true));
 489  
                                                 continue;
 490  
                                         }
 491  
                                 }
 492  
 
 493  
                                 if (c == 'f' && (part.equals("flowy") || part.equals("flowx"))) {
 494  
                                         cc.setFlowX(part.charAt(4) == 'x' ? Boolean.TRUE : Boolean.FALSE);
 495  
                                         continue;
 496  
                                 }
 497  
 
 498  
                                 if (c == 's') {
 499  
                                         ix = startsWithLenient(part, "skip", 4, true);
 500  
                                         if (ix > -1) {
 501  
                                                 String num = part.substring(ix).trim();
 502  
                                                 cc.setSkip(num.length() != 0 ? Integer.parseInt(num) : 1);
 503  
                                                 continue;
 504  
                                         }
 505  
 
 506  
                                         ix = startsWithLenient(part, "split", 5, true);
 507  
                                         if (ix > -1) {
 508  
                                                 String split = part.substring(ix).trim();
 509  
                                                 cc.setSplit(split.length() > 0 ? Integer.parseInt(split) : LayoutUtil.INF);
 510  
                                                 continue;
 511  
                                         }
 512  
 
 513  
                                         if (part.equals("south")) {
 514  
                                                 cc.setDockSide(2);
 515  
                                                 continue;
 516  
                                         }
 517  
 
 518  
                                         ix = startsWithLenient(part, new String[]{"spany", "sy"}, new int[]{5, 2}, true);
 519  
                                         if (ix > -1) {
 520  
                                                 cc.setSpanY(parseSpan(part.substring(ix).trim()));
 521  
                                                 continue;
 522  
                                         }
 523  
 
 524  
                                         ix = startsWithLenient(part, new String[]{"spanx", "sx"}, new int[]{5, 2}, true);
 525  
                                         if (ix > -1) {
 526  
                                                 cc.setSpanX(parseSpan(part.substring(ix).trim()));
 527  
                                                 continue;
 528  
                                         }
 529  
 
 530  
                                         ix = startsWithLenient(part, "span", 4, true);
 531  
                                         if (ix > -1) {
 532  
                                                 String[] spans = toTrimmedTokens(part.substring(ix).trim(), ' ');
 533  
                                                 cc.setSpanX(spans[0].length() > 0 ? Integer.parseInt(spans[0]) : LayoutUtil.INF);
 534  
                                                 cc.setSpanY(spans.length > 1 ? Integer.parseInt(spans[1]) : 1);
 535  
                                                 continue;
 536  
                                         }
 537  
 
 538  
                                         ix = startsWithLenient(part, "shrinkx", 7, true);
 539  
                                         if (ix > -1) {
 540  
                                                 cc.getHorizontal().setShrink(parseFloat(part.substring(ix).trim(), ResizeConstraint.WEIGHT_100));
 541  
                                                 continue;
 542  
                                         }
 543  
 
 544  
                                         ix = startsWithLenient(part, "shrinky", 7, true);
 545  
                                         if (ix > -1) {
 546  
                                                 cc.getVertical().setShrink(parseFloat(part.substring(ix).trim(), ResizeConstraint.WEIGHT_100));
 547  
                                                 continue;
 548  
                                         }
 549  
 
 550  
                                         ix = startsWithLenient(part, "shrink", 6, false);
 551  
                                         if (ix > -1) {
 552  
                                                 String[] shrinks = toTrimmedTokens(part.substring(ix).trim(), ' ');
 553  
                                                 cc.getHorizontal().setShrink(parseFloat(part.substring(ix).trim(), ResizeConstraint.WEIGHT_100));
 554  
                                                 if (shrinks.length > 1)
 555  
                                                         cc.getVertical().setShrink(parseFloat(part.substring(ix).trim(), ResizeConstraint.WEIGHT_100));
 556  
                                                 continue;
 557  
                                         }
 558  
 
 559  
                                         ix = startsWithLenient(part, new String[]{"shrinkprio", "shp"}, new int[]{10, 3}, true);
 560  
                                         if (ix > -1) {
 561  
                                                 String sp = part.substring(ix).trim();
 562  
                                                 if (sp.startsWith("x") || sp.startsWith("y")) { // To gandle "gpx", "gpy", "shrinkpriorityx", shrinkpriorityy"
 563  
                                                         (sp.startsWith("x") ? cc.getHorizontal() : cc.getVertical()).setShrinkPriority(Integer.parseInt(sp.substring(2)));
 564  
                                                 } else {
 565  
                                                         String[] shrinks = toTrimmedTokens(sp, ' ');
 566  
                                                         cc.getHorizontal().setShrinkPriority(Integer.parseInt(shrinks[0]));
 567  
                                                         if (shrinks.length > 1)
 568  
                                                                 cc.getVertical().setShrinkPriority(Integer.parseInt(shrinks[1]));
 569  
                                                 }
 570  
                                                 continue;
 571  
                                         }
 572  
 
 573  
                                         ix = startsWithLenient(part, new String[]{"sizegroupx", "sizegroupy", "sgx", "sgy"}, new int[]{9, 9, 2, 2}, true);
 574  
                                         if (ix > -1) {
 575  
                                                 String sg = part.substring(ix).trim();
 576  
                                                 char lc = part.charAt(ix - 1);
 577  
                                                 if (lc != 'y')
 578  
                                                         cc.getHorizontal().setSizeGroup(sg);
 579  
                                                 if (lc != 'x')
 580  
                                                         cc.getVertical().setSizeGroup(sg);
 581  
                                                 continue;
 582  
                                         }
 583  
                                 }
 584  
 
 585  
                                 if (c == 'g') {
 586  
                                         ix = startsWithLenient(part, "growx", 5, true);
 587  
                                         if (ix > -1) {
 588  
                                                 cc.getHorizontal().setGrow(parseFloat(part.substring(ix).trim(), ResizeConstraint.WEIGHT_100));
 589  
                                                 continue;
 590  
                                         }
 591  
 
 592  
                                         ix = startsWithLenient(part, "growy", 5, true);
 593  
                                         if (ix > -1) {
 594  
                                                 cc.getVertical().setGrow(parseFloat(part.substring(ix).trim(), ResizeConstraint.WEIGHT_100));
 595  
                                                 continue;
 596  
                                         }
 597  
 
 598  
                                         ix = startsWithLenient(part, "grow", 4, false);
 599  
                                         if (ix > -1) {
 600  
                                                 String[] grows = toTrimmedTokens(part.substring(ix).trim(), ' ');
 601  
                                                 cc.getHorizontal().setGrow(parseFloat(grows[0], ResizeConstraint.WEIGHT_100));
 602  
                                                 cc.getVertical().setGrow(parseFloat(grows.length > 1 ? grows[1] : "", ResizeConstraint.WEIGHT_100));
 603  
                                                 continue;
 604  
                                         }
 605  
 
 606  
                                         ix = startsWithLenient(part, new String[]{"growprio", "gp"}, new int[]{8, 2}, true);
 607  
                                         if (ix > -1) {
 608  
                                                 String gp = part.substring(ix).trim();
 609  
                                                 char c0 = gp.length() > 0 ? gp.charAt(0) : ' ';
 610  
                                                 if (c0 == 'x' || c0 == 'y') { // To gandle "gpx", "gpy", "growpriorityx", growpriorityy"
 611  
                                                         (c0 == 'x' ? cc.getHorizontal() : cc.getVertical()).setGrowPriority(Integer.parseInt(gp.substring(2)));
 612  
                                                 } else {
 613  
                                                         String[] grows = toTrimmedTokens(gp, ' ');
 614  
                                                         cc.getHorizontal().setGrowPriority(Integer.parseInt(grows[0]));
 615  
                                                         if (grows.length > 1)
 616  
                                                                 cc.getVertical().setGrowPriority(Integer.parseInt(grows[1]));
 617  
                                                 }
 618  
                                                 continue;
 619  
                                         }
 620  
 
 621  
                                         if (part.startsWith("gap")) {
 622  
                                                 BoundSize[] gaps = parseGaps(part); // Changes order!!
 623  
                                                 if (gaps[0] != null)
 624  
                                                         cc.getVertical().setGapBefore(gaps[0]);
 625  
                                                 if (gaps[1] != null)
 626  
                                                         cc.getHorizontal().setGapBefore(gaps[1]);
 627  
                                                 if (gaps[2] != null)
 628  
                                                         cc.getVertical().setGapAfter(gaps[2]);
 629  
                                                 if (gaps[3] != null)
 630  
                                                         cc.getHorizontal().setGapAfter(gaps[3]);
 631  
                                                 continue;
 632  
                                         }
 633  
                                 }
 634  
 
 635  
                                 if (c == 'a') {
 636  
                                         ix = startsWithLenient(part, new String[]{"aligny", "ay"}, new int[]{6, 2}, true);
 637  
                                         if (ix > -1) {
 638  
                                                 cc.getVertical().setAlign(parseUnitValueOrAlign(part.substring(ix).trim(), false, null));
 639  
                                                 continue;
 640  
                                         }
 641  
 
 642  
                                         ix = startsWithLenient(part, new String[]{"alignx", "ax"}, new int[]{6, 2}, true);
 643  
                                         if (ix > -1) {
 644  
                                                 cc.getHorizontal().setAlign(parseUnitValueOrAlign(part.substring(ix).trim(), true, null));
 645  
                                                 continue;
 646  
                                         }
 647  
 
 648  
                                         ix = startsWithLenient(part, "align", 2, true);
 649  
                                         if (ix > -1) {
 650  
                                                 String[] gaps = toTrimmedTokens(part.substring(ix).trim(), ' ');
 651  
                                                 cc.getHorizontal().setAlign(parseUnitValueOrAlign(gaps[0], true, null));
 652  
                                                 if (gaps.length > 1)
 653  
                                                         cc.getVertical().setAlign(parseUnitValueOrAlign(gaps[1], false, null));
 654  
                                                 continue;
 655  
                                         }
 656  
                                 }
 657  
 
 658  
                                 if ((c == 'x' || c == 'y') && part.length() > 2) {
 659  
                                         char c2 = part.charAt(1);
 660  
                                         if (c2 == ' ' || (c2 == '2' && part.charAt(2) == ' ')) {
 661  
                                                 if (cc.getPos() == null) {
 662  
                                                         cc.setPos(new UnitValue[4]);
 663  
                                                 } else if (cc.isBoundsInGrid() == false) {
 664  
                                                         throw new IllegalArgumentException("Cannot combine 'position' with 'x/y/x2/y2' keywords.");
 665  
                                                 }
 666  
 
 667  
                                                 int edge = (c == 'x' ? 0 : 1) + (c2 == '2' ? 2 : 0);
 668  
                                                 UnitValue[] pos = cc.getPos();
 669  
                                                 pos[edge] = parseUnitValue(part.substring(2).trim(), null, c == 'x');
 670  
                                                 cc.setPos(pos);
 671  
                                                 cc.setBoundsInGrid(true);
 672  
                                                 continue;
 673  
                                         }
 674  
                                 }
 675  
 
 676  
                                 if (c == 'c') {
 677  
                                         ix = startsWithLenient(part, "cell", 4, true);
 678  
                                         if (ix > -1) {
 679  
                                                 String[] grs = toTrimmedTokens(part.substring(ix).trim(), ' ');
 680  
                                                 if (grs.length < 2)
 681  
                                                         throw new IllegalArgumentException("At least two integers must follow " + part);
 682  
                                                 cc.setCellX(Integer.parseInt(grs[0]));
 683  
                                                 cc.setCellY(Integer.parseInt(grs[1]));
 684  
                                                 if (grs.length > 2)
 685  
                                                         cc.setSpanX(Integer.parseInt(grs[2]));
 686  
                                                 if (grs.length > 3)
 687  
                                                         cc.setSpanY(Integer.parseInt(grs[3]));
 688  
                                                 continue;
 689  
                                         }
 690  
                                 }
 691  
 
 692  
                                 if (c == 'p') {
 693  
                                         ix = startsWithLenient(part, "pos", 3, true);
 694  
                                         if (ix > -1) {
 695  
                                                 if (cc.getPos() != null && cc.isBoundsInGrid())
 696  
                                                         throw new IllegalArgumentException("Can not combine 'pos' with 'x/y/x2/y2' keywords.");
 697  
 
 698  
                                                 String[] pos = toTrimmedTokens(part.substring(ix).trim(), ' ');
 699  
                                                 UnitValue[] bounds = new UnitValue[4];
 700  
                                                 for (int j = 0; j < pos.length; j++)
 701  
                                                         bounds[j] = parseUnitValue(pos[j], null, j % 2 == 0);
 702  
 
 703  
                                                 if (bounds[0] == null && bounds[2] == null || bounds[1] == null && bounds[3] == null)
 704  
                                                         throw new IllegalArgumentException("Both x and x2 or y and y2 can not be null!");
 705  
 
 706  
                                                 cc.setPos(bounds);
 707  
                                                 cc.setBoundsInGrid(false);
 708  
                                                 continue;
 709  
                                         }
 710  
 
 711  
                                         ix = startsWithLenient(part, "pad", 3, true);
 712  
                                         if (ix > -1) {
 713  
                                                 UnitValue[] p = parseInsets(part.substring(ix).trim(), false);
 714  
                                                 cc.setPadding(new UnitValue[]{
 715  
                                                         p[0],
 716  
                                                         p.length > 1 ? p[1] : null,
 717  
                                                         p.length > 2 ? p[2] : null,
 718  
                                                         p.length > 3 ? p[3] : null});
 719  
                                                 continue;
 720  
                                         }
 721  
 
 722  
                                         ix = startsWithLenient(part, "pushx", 5, true);
 723  
                                         if (ix > -1) {
 724  
                                                 cc.setPushX(parseFloat(part.substring(ix).trim(), ResizeConstraint.WEIGHT_100));
 725  
                                                 continue;
 726  
                                         }
 727  
 
 728  
                                         ix = startsWithLenient(part, "pushy", 5, true);
 729  
                                         if (ix > -1) {
 730  
                                                 cc.setPushY(parseFloat(part.substring(ix).trim(), ResizeConstraint.WEIGHT_100));
 731  
                                                 continue;
 732  
                                         }
 733  
 
 734  
                                         ix = startsWithLenient(part, "push", 4, false);
 735  
                                         if (ix > -1) {
 736  
                                                 String[] pushs = toTrimmedTokens(part.substring(ix).trim(), ' ');
 737  
                                                 cc.setPushX(parseFloat(pushs[0], ResizeConstraint.WEIGHT_100));
 738  
                                                 cc.setPushY(parseFloat(pushs.length > 1 ? pushs[1] : "", ResizeConstraint.WEIGHT_100));
 739  
                                                 continue;
 740  
                                         }
 741  
                                 }
 742  
 
 743  
                                 if (c == 't') {
 744  
                                         ix = startsWithLenient(part, "tag", 3, true);
 745  
                                         if (ix > -1) {
 746  
                                                 cc.setTag(part.substring(ix).trim());
 747  
                                                 continue;
 748  
                                         }
 749  
                                 }
 750  
 
 751  
                                 if (c == 'w' || c == 'h') {
 752  
                                         if (part.equals("wrap")) {
 753  
                                                 cc.setWrap(true);
 754  
                                                 continue;
 755  
                                         }
 756  
 
 757  
                                         if (part.startsWith("wrap ")) {
 758  
                                                 String gapSz = part.substring(5).trim();
 759  
                                                 cc.setWrapGapSize(parseBoundSize(gapSz, true, true));
 760  
                                                 continue;
 761  
                                         }
 762  
 
 763  
                                         boolean isHor = c == 'w';
 764  
                                         if (isHor && (part.startsWith("w ") || part.startsWith("width "))) {
 765  
                                                 String uvStr = part.substring(part.charAt(1) == ' ' ? 2 : 6).trim();
 766  
                                                 cc.getHorizontal().setSize(parseBoundSize(uvStr, false, true));
 767  
                                                 continue;
 768  
                                         }
 769  
 
 770  
                                         if (!isHor && (part.startsWith("h ") || part.startsWith("height "))) {
 771  
                                                 String uvStr = part.substring(part.charAt(1) == ' ' ? 2 : 7).trim();
 772  
                                                 cc.getVertical().setSize(parseBoundSize(uvStr, false, false));
 773  
                                                 continue;
 774  
                                         }
 775  
 
 776  
                                         if (part.startsWith("wmin ") || part.startsWith("wmax ") || part.startsWith("hmin ") || part.startsWith("hmax ")) {
 777  
                                                 String uvStr = part.substring(5).trim();
 778  
                                                 if (uvStr.length() > 0) {
 779  
                                                         UnitValue uv = parseUnitValue(uvStr, null, isHor);
 780  
                                                         boolean isMin = part.charAt(3) == 'n';
 781  
                                                         DimConstraint dc = isHor ? cc.getHorizontal() : cc.getVertical();
 782  
                                                         dc.setSize(new BoundSize(
 783  
                                                                 isMin ? uv : dc.getSize().getMin(),
 784  
                                                                 dc.getSize().getPreferred(),
 785  
                                                                 isMin ? (dc.getSize().getMax()) : uv,
 786  
                                                                 uvStr
 787  
                                                         ));
 788  
                                                         continue;
 789  
                                                 }
 790  
                                         }
 791  
 
 792  
                                         if (part.equals("west")) {
 793  
                                                 cc.setDockSide(1);
 794  
                                                 continue;
 795  
                                         }
 796  
 
 797  
                                         if (part.startsWith("hidemode ")) {
 798  
                                                 cc.setHideMode(Integer.parseInt(part.substring(9)));
 799  
                                                 continue;
 800  
                                         }
 801  
                                 }
 802  
 
 803  
                                 if (c == 'i' && part.startsWith("id ")) {
 804  
                                         cc.setId(part.substring(3).trim());
 805  
                                         int dIx = cc.getId().indexOf('.');
 806  
                                         if (dIx == 0 || dIx == cc.getId().length() - 1)
 807  
                                                 throw new IllegalArgumentException("Dot must not be first or last!");
 808  
 
 809  
                                         continue;
 810  
                                 }
 811  
 
 812  
                                 if (c == 'e') {
 813  
                                         if (part.equals("east")) {
 814  
                                                 cc.setDockSide(3);
 815  
                                                 continue;
 816  
                                         }
 817  
 
 818  
                                         if (part.equals("external")) {
 819  
                                                 cc.setExternal(true);
 820  
                                                 continue;
 821  
                                         }
 822  
 
 823  
                                         ix = startsWithLenient(part, new String[]{"endgroupx", "endgroupy", "egx", "egy"}, new int[]{-1, -1, -1, -1}, true);
 824  
                                         if (ix > -1) {
 825  
                                                 String sg = part.substring(ix).trim();
 826  
                                                 char lc = part.charAt(ix - 1);
 827  
                                                 DimConstraint dc = (lc == 'x' ? cc.getHorizontal() : cc.getVertical());
 828  
                                                 dc.setEndGroup(sg);
 829  
                                                 continue;
 830  
                                         }
 831  
                                 }
 832  
 
 833  
                                 if (c == 'd') {
 834  
                                         if (part.equals("dock north")) {
 835  
                                                 cc.setDockSide(0);
 836  
                                                 continue;
 837  
                                         }
 838  
                                         if (part.equals("dock west")) {
 839  
                                                 cc.setDockSide(1);
 840  
                                                 continue;
 841  
                                         }
 842  
                                         if (part.equals("dock south")) {
 843  
                                                 cc.setDockSide(2);
 844  
                                                 continue;
 845  
                                         }
 846  
                                         if (part.equals("dock east")) {
 847  
                                                 cc.setDockSide(3);
 848  
                                                 continue;
 849  
                                         }
 850  
 
 851  
                                         if (part.equals("dock center")) {
 852  
                                                 cc.getHorizontal().setGrow(100f);
 853  
                                                 cc.getVertical().setGrow(100f);
 854  
                                                 cc.setPushX(100f);
 855  
                                                 cc.setPushY(100f);
 856  
                                                 continue;
 857  
                                         }
 858  
                                 }
 859  
 
 860  
                                 UnitValue horAlign = parseAlignKeywords(part, true);
 861  
                                 if (horAlign != null) {
 862  
                                         cc.getHorizontal().setAlign(horAlign);
 863  
                                         continue;
 864  
                                 }
 865  
 
 866  
                                 UnitValue verAlign = parseAlignKeywords(part, false);
 867  
                                 if (verAlign != null) {
 868  
                                         cc.getVertical().setAlign(verAlign);
 869  
                                         continue;
 870  
                                 }
 871  
 
 872  
                                 throw new IllegalArgumentException("Unknown keyword.");
 873  
 
 874  
                         } catch (Exception ex) {
 875  
                                 throw new IllegalArgumentException("Illegal Constraint: '" + part + "'\n" + ex.getMessage());
 876  
                         }
 877  
                 }
 878  
 
 879  
 //                cc = (CC) serializeTest(cc);
 880  
 
 881  
                 return cc;
 882  
         }
 883  
 
 884  
         /** Parses insets which consists of 1-4 <code>UnitValue</code>s.
 885  
          * @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.
 886  
          * @param acceptPanel If "panel" and "dialog" should be accepted. They are used to access platform defaults.
 887  
          * @return An array of length 4 with the parsed insets.
 888  
          * @throws IllegalArgumentException if the parsing could not be done.
 889  
          */
 890  
         public static UnitValue[] parseInsets(String s, boolean acceptPanel)
 891  
         {
 892  
                 if (s.length() == 0 || s.equals("dialog") || s.equals("panel")) {
 893  
                         if (acceptPanel == false)
 894  
                                 throw new IllegalAccessError("Insets now allowed: " + s + "\n");
 895  
 
 896  
                         boolean isPanel = s.startsWith("p");
 897  
                         UnitValue[] ins = new UnitValue[4];
 898  
                         for (int j = 0; j < 4; j++)
 899  
                                 ins[j] = isPanel ? PlatformDefaults.getPanelInsets(j) : PlatformDefaults.getDialogInsets(j);
 900  
 
 901  
                         return ins;
 902  
                 } else {
 903  
                         String[] insS = toTrimmedTokens(s, ' ');
 904  
                         UnitValue[] ins = new UnitValue[4];
 905  
                         for (int j = 0; j < 4; j++) {
 906  
                                 UnitValue insSz = parseUnitValue(insS[j < insS.length ? j : insS.length - 1], UnitValue.ZERO, j % 2 == 1);
 907  
                                 ins[j] = insSz != null ? insSz : PlatformDefaults.getPanelInsets(j);
 908  
                         }
 909  
                         return ins;
 910  
                 }
 911  
         }
 912  
 
 913  
         /** Parses gaps.
 914  
          * @param s The string that contains gap information. Should start with "gap".
 915  
          * @return The gaps as specified in <code>s</code>. Indexed: <code>[top,left,bottom,right][min,pref,max]</code> or
 916  
          * [before,after][min,pref,max] if <code>oneDim</code> is true.
 917  
          */
 918  
         private static BoundSize[] parseGaps(String s)
 919  
         {
 920  
                 BoundSize[] ret = new BoundSize[4];
 921  
 
 922  
                 int ix = startsWithLenient(s, "gaptop", -1, true);
 923  
                 if (ix > -1) {
 924  
                         s = s.substring(ix).trim();
 925  
                         ret[0] = parseBoundSize(s, true, false);
 926  
                         return ret;
 927  
                 }
 928  
 
 929  
                 ix = startsWithLenient(s, "gapleft", -1, true);
 930  
                 if (ix > -1) {
 931  
                         s = s.substring(ix).trim();
 932  
                         ret[1] = parseBoundSize(s, true, true);
 933  
                         return ret;
 934  
                 }
 935  
 
 936  
                 ix = startsWithLenient(s, "gapbottom", -1, true);
 937  
                 if (ix > -1) {
 938  
                         s = s.substring(ix).trim();
 939  
                         ret[2] = parseBoundSize(s, true, false);
 940  
                         return ret;
 941  
                 }
 942  
 
 943  
                 ix = startsWithLenient(s, "gapright", -1, true);
 944  
                 if (ix > -1) {
 945  
                         s = s.substring(ix).trim();
 946  
                         ret[3] = parseBoundSize(s, true, true);
 947  
                         return ret;
 948  
                 }
 949  
 
 950  
                 ix = startsWithLenient(s, "gapbefore", -1, true);
 951  
                 if (ix > -1) {
 952  
                         s = s.substring(ix).trim();
 953  
                         ret[1] = parseBoundSize(s, true, true);
 954  
                         return ret;
 955  
                 }
 956  
 
 957  
                 ix = startsWithLenient(s, "gapafter", -1, true);
 958  
                 if (ix > -1) {
 959  
                         s = s.substring(ix).trim();
 960  
                         ret[3] = parseBoundSize(s, true, true);
 961  
                         return ret;
 962  
                 }
 963  
 
 964  
                 ix = startsWithLenient(s, new String[] {"gapx", "gapy"}, null, true);
 965  
                 if (ix > -1) {
 966  
                         boolean x = s.charAt(3) == 'x';
 967  
                         String[] gaps = toTrimmedTokens(s.substring(ix).trim(), ' ');
 968  
                         ret[x ? 1 : 0] = parseBoundSize(gaps[0], true, x);
 969  
                         if (gaps.length > 1)
 970  
                                 ret[x ? 3 : 2] = parseBoundSize(gaps[1], true, !x);
 971  
                         return ret;
 972  
                 }
 973  
 
 974  
                 ix = startsWithLenient(s, "gap ", 1, true);
 975  
                 if (ix > -1) {
 976  
                         String[] gaps = toTrimmedTokens(s.substring(ix).trim(), ' ');
 977  
 
 978  
                         ret[1] = parseBoundSize(gaps[0], true, true);   // left
 979  
                         if (gaps.length > 1) {
 980  
                                 ret[3] = parseBoundSize(gaps[1], true, false);   // right
 981  
                                 if (gaps.length > 2) {
 982  
                                         ret[0] = parseBoundSize(gaps[2], true, true);   // top
 983  
                                         if (gaps.length > 3)
 984  
                                                 ret[2] = parseBoundSize(gaps[3], true, false);   // bottom
 985  
                                 }
 986  
                         }
 987  
                         return ret;
 988  
                 }
 989  
 
 990  
                 throw new IllegalArgumentException("Unknown Gap part: '" + s + "'");
 991  
         }
 992  
 
 993  
         private static int parseSpan(String s)
 994  
         {
 995  
                 return s.length() > 0 ? Integer.parseInt(s) : LayoutUtil.INF;
 996  
         }
 997  
 
 998  
         private static Float parseFloat(String s, Float nullVal)
 999  
         {
 1000  
                 return s.length() > 0 ? new Float(Float.parseFloat(s)) : nullVal;
 1001  
         }
 1002  
 
 1003  
         /** Parses a single "min:pref:max" value. May look something like <code>"10px:20lp:30%"</code> or <code>"pref!"</code>.
 1004  
          * @param s The string to parse. Not <code>null</code>.
 1005  
          * @param isGap If this bound size is a gap (different empty string handling).
 1006  
          * @param isHor If the size is for the horizontal dimension.
 1007  
          * @return A bound size that may be <code>null</code> if the string was "null", "n" or <code>null</code>.
 1008  
          */
 1009  
         public static BoundSize parseBoundSize(String s, boolean isGap, boolean isHor)
 1010  
         {
 1011  
                 if (s.length() == 0 || s.equals("null") || s.equals("n"))
 1012  
                         return null;
 1013  
 
 1014  
                 String cs = s;
 1015  
                 boolean push = false;
 1016  
                 if (s.endsWith("push")) {
 1017  
                         push = true;
 1018  
                         int l = s.length();
 1019  
                         s = s.substring(0, l - (s.endsWith(":push") ? 5 : 4));
 1020  
                         if (s.length() == 0)
 1021  
                                 return new BoundSize(null, null, null, true, cs);
 1022  
                 }
 1023  
 
 1024  
                 String[] sizes = toTrimmedTokens(s, ':');
 1025  
                 String s0 = sizes[0];
 1026  
 
 1027  
                 if (sizes.length == 1) {
 1028  
                         boolean hasEM = s0.endsWith("!");
 1029  
                         if (hasEM)
 1030  
                                 s0 = s0.substring(0, s0.length() - 1);
 1031  
                         UnitValue uv = parseUnitValue(s0, null, isHor);
 1032  
                         return new BoundSize(((isGap || hasEM) ? uv : null), uv, (hasEM ? uv : null), push, cs);
 1033  
 
 1034  
                 } else if (sizes.length == 2) {
 1035  
                         return new BoundSize(parseUnitValue(s0, null, isHor), parseUnitValue(sizes[1], null, isHor), null, push, cs);
 1036  
                 } else if (sizes.length == 3) {
 1037  
                         return new BoundSize(parseUnitValue(s0, null, isHor), parseUnitValue(sizes[1], null, isHor), parseUnitValue(sizes[2], null, isHor), push, cs);
 1038  
                 } else {
 1039  
                         throw new IllegalArgumentException("Min:Preferred:Max size section must contain 0, 1 or 2 colons. '" + cs + "'");
 1040  
                 }
 1041  
         }
 1042  
 
 1043  
         /** Parses a single unit value that may also be an alignment as parsed by {@link #parseAlignKeywords(String, boolean)}.
 1044  
          * @param s The string to parse. Not <code>null</code>. May look something like <code>"10px"</code> or <code>"5dlu"</code>.
 1045  
          * @param isHor If the value is for the horizontal dimension.
 1046  
          * @param emptyReplacement A replacement if <code>s</code> is empty. May be <code>null</code>.
 1047  
          * @return The parsed unit value. May be <code>null</code>.
 1048  
          */
 1049  
         public static UnitValue parseUnitValueOrAlign(String s, boolean isHor, UnitValue emptyReplacement)
 1050  
         {
 1051  
                 if (s.length() == 0)
 1052  
                         return emptyReplacement;
 1053  
 
 1054  
                 UnitValue align = parseAlignKeywords(s, isHor);
 1055  
                 if (align != null)
 1056  
                         return align;
 1057  
 
 1058  
                 return parseUnitValue(s, emptyReplacement, isHor);
 1059  
         }
 1060  
 
 1061  
         /** Parses a single unit value. E.g. "10px" or "5in"
 1062  
          * @param s The string to parse. Not <code>null</code>. May look something like <code>"10px"</code> or <code>"5dlu"</code>.
 1063  
          * @param isHor If the value is for the horizontal dimension.
 1064  
          * @return The parsed unit value. <code>null</code> is empty string,
 1065  
          */
 1066  
         public static UnitValue parseUnitValue(String s, boolean isHor)
 1067  
         {
 1068  
                 return parseUnitValue(s, null, isHor);
 1069  
         }
 1070  
 
 1071  
         /** Parses a single unit value.
 1072  
          * @param s The string to parse. May be <code>null</code>. May look something like <code>"10px"</code> or <code>"5dlu"</code>.
 1073  
          * @param emptyReplacement A replacement <code>s</code> is empty or <code>null</code>. May be <code>null</code>.
 1074  
          * @param isHor If the value is for the horizontal dimension.
 1075  
          * @return The parsed unit value. May be <code>null</code>.
 1076  
          */
 1077  
         private static UnitValue parseUnitValue(String s, UnitValue emptyReplacement, boolean isHor)
 1078  
         {
 1079  
                 if (s == null || s.length() == 0)
 1080  
                         return emptyReplacement;
 1081  
 
 1082  
                 String cs = s; // Save creation string.
 1083  
                 char c0 = s.charAt(0);
 1084  
 
 1085  
                 // Remove start and end parentheses, if there.
 1086  
                 if (c0 == '(' && s.charAt(s.length() - 1) == ')')
 1087  
                         s = s.substring(1, s.length() - 1);
 1088  
 
 1089  
                 if (c0 == 'n' && (s.equals("null") || s.equals("n")))
 1090  
                         return null;
 1091  
 
 1092  
                 if (c0 == 'i' && s.equals("inf"))
 1093  
                         return UnitValue.INF;
 1094  
 
 1095  
                 int oper = getOper(s);
 1096  
                 boolean inline = oper == UnitValue.ADD || oper == UnitValue.SUB || oper == UnitValue.MUL || oper == UnitValue.DIV;
 1097  
 
 1098  
                 if (oper != UnitValue.STATIC) {  // It is a multi-value
 1099  
 
 1100  
                         String[] uvs;
 1101  
                         if (inline == false) {   // If the format is of type "opr(xxx,yyy)" (compared to in-line "10%+15px")
 1102  
                                 String sub = s.substring(4, s.length() - 1).trim();
 1103  
                                 uvs = toTrimmedTokens(sub, ',');
 1104  
                                 if (uvs.length == 1)
 1105  
                                         return parseUnitValue(sub, null, isHor);
 1106  
                         } else {
 1107  
                                 char delim;
 1108  
                                 if (oper == UnitValue.ADD) {
 1109  
                                         delim = '+';
 1110  
                                 } else if (oper == UnitValue.SUB) {
 1111  
                                         delim = '-';
 1112  
                                 } else if (oper == UnitValue.MUL) {
 1113  
                                         delim = '*';
 1114  
                                 } else {    // div left
 1115  
                                         delim = '/';
 1116  
                                 }
 1117  
                                 uvs = toTrimmedTokens(s, delim);
 1118  
                                 if (uvs.length > 2) {   // More than one +-*/.
 1119  
                                         String last = uvs[uvs.length - 1];
 1120  
                                         String first = s.substring(0, s.length() - last.length() - 1);
 1121  
                                         uvs = new String[] {first, last};
 1122  
                                 }
 1123  
                         }
 1124  
 
 1125  
                         if (uvs.length != 2)
 1126  
                                 throw new IllegalArgumentException("Malformed UnitValue: '" + s + "'");
 1127  
 
 1128  
                         UnitValue sub1 = parseUnitValue(uvs[0], null, isHor);
 1129  
                         UnitValue sub2 = parseUnitValue(uvs[1], null, isHor);
 1130  
 
 1131  
                         if (sub1 == null || sub2 == null)
 1132  
                                 throw new IllegalArgumentException("Malformed UnitValue. Must be two sub-values: '" + s + "'");
 1133  
 
 1134  
                         return new UnitValue(isHor, oper, sub1, sub2, cs);
 1135  
                 } else {
 1136  
                         try {
 1137  
                                 String[] numParts = getNumTextParts(s);
 1138  
                                 float value = numParts[0].length() > 0 ? Float.parseFloat(numParts[0]) : 1;     // e.g. "related" has no number part..
 1139  
 
 1140  
                                 return new UnitValue(value, numParts[1], isHor, oper, cs);
 1141  
 
 1142  
                         } catch(Exception e) {
 1143  
                                 throw new IllegalArgumentException("Malformed UnitValue: '" + s + "'");
 1144  
                         }
 1145  
                 }
 1146  
         }
 1147  
 
 1148  
         /** Parses alignment keywords and returns the appropriate <code>UnitValue</code>.
 1149  
          * @param s The string to parse. Not <code>null</code>.
 1150  
          * @param isHor If alignments for horizontal is checked. <code>false</code> means vertical.
 1151  
          * @return The unit value or <code>null</code> if not recognized (no exception).
 1152  
          */
 1153  
         static UnitValue parseAlignKeywords(String s, boolean isHor)
 1154  
         {
 1155  
                 if (startsWithLenient(s, "center", 1, false) != -1)
 1156  
                         return UnitValue.CENTER;
 1157  
 
 1158  
                 if (isHor) {
 1159  
                         if (startsWithLenient(s, "left", 1, false) != -1)
 1160  
                                 return UnitValue.LEFT;
 1161  
 
 1162  
                         if (startsWithLenient(s, "right", 1, false) != -1)
 1163  
                                 return UnitValue.RIGHT;
 1164  
 
 1165  
                         if (startsWithLenient(s, "leading", 4, false) != -1)
 1166  
                                 return UnitValue.LEADING;
 1167  
 
 1168  
                         if (startsWithLenient(s, "trailing", 5, false) != -1)
 1169  
                                 return UnitValue.TRAILING;
 1170  
 
 1171  
                         if (startsWithLenient(s, "label", 5, false) != -1)
 1172  
                                 return UnitValue.LABEL;
 1173  
 
 1174  
                 } else {
 1175  
 
 1176  
                         if (startsWithLenient(s, "baseline", 4, false) != -1)
 1177  
                                 return UnitValue.BASELINE_IDENTITY;
 1178  
 
 1179  
                         if (startsWithLenient(s, "top", 1, false) != -1)
 1180  
                                 return UnitValue.TOP;
 1181  
 
 1182  
                         if (startsWithLenient(s, "bottom", 1, false) != -1)
 1183  
                                 return UnitValue.BOTTOM;
 1184  
                 }
 1185  
 
 1186  
                 return null;
 1187  
         }
 1188  
 
 1189  
         /** Splits a text-number combination such as "hello 10.0" into <code>{"hello", "10.0"}</code>.
 1190  
          * @param s The string to split. Not <code>null</code>. Needs be be reasonably formatted since the method
 1191  
          * only finds the first 0-9 or . and cuts the string in half there.
 1192  
          * @return Always length 2 and no <code>null</code> elements. Elements are "" if no part found.
 1193  
          */
 1194  
         private static String[] getNumTextParts(String s)
 1195  
         {
 1196  
                 for (int i = 0, iSz = s.length(); i < iSz; i++) {
 1197  
                         char c = s.charAt(i);
 1198  
                         if (c == ' ')
 1199  
                                 throw new IllegalArgumentException("Space in UnitValue: '" + s + "'");
 1200  
 
 1201  
                         if ((c < '0' || c > '9') && c != '.' && c != '-')
 1202  
                                 return new String[] {s.substring(0, i).trim(), s.substring(i).trim()};
 1203  
                 }
 1204  
                 return new String[] {s, ""};
 1205  
         }
 1206  
 
 1207  
         /** Returns the operation depending on the start character.
 1208  
          * @param s The string to check. Not <code>null</code>.
 1209  
          * @return E.g. UnitValue.ADD, UnitValue.SUB or UnitValue.STATIC. Returns negative value for in-line operations.
 1210  
          */
 1211  
         private static int getOper(String s)
 1212  
         {
 1213  
                 int len = s.length();
 1214  
                 if (len < 3)
 1215  
                         return UnitValue.STATIC;
 1216  
 
 1217  
                 if (len > 5 && s.charAt(3) == '(' && s.charAt(len - 1) == ')') {
 1218  
                         if (s.startsWith("min("))
 1219  
                                 return UnitValue.MIN;
 1220  
 
 1221  
                         if (s.startsWith("max("))
 1222  
                                 return UnitValue.MAX;
 1223  
 
 1224  
                         if (s.startsWith("mid("))
 1225  
                                 return UnitValue.MID;
 1226  
                 }
 1227  
 
 1228  
                 // Try in-line add/sub. E.g. "pref+10px".
 1229  
                 for (int j = 0; j < 2; j++) {   // First +-   then */   (precedence)
 1230  
                         for (int i = len - 1, p = 0; i > 0; i--) {
 1231  
                                 char c = s.charAt(i);
 1232  
                                 if (c == ')') {
 1233  
                                         p++;
 1234  
                                 } else if (c == '(') {
 1235  
                                         p--;
 1236  
                                 } else if (p == 0) {
 1237  
                                         if (j == 0) {
 1238  
                                                 if (c == '+')
 1239  
                                                         return UnitValue.ADD;
 1240  
                                                 if (c == '-')
 1241  
                                                         return UnitValue.SUB;
 1242  
                                         } else {
 1243  
                                                 if (c == '*')
 1244  
                                                         return UnitValue.MUL;
 1245  
                                                 if (c == '/')
 1246  
                                                         return UnitValue.DIV;
 1247  
                                         }
 1248  
                                 }
 1249  
                         }
 1250  
                 }
 1251  
                 return UnitValue.STATIC;
 1252  
         }
 1253  
 
 1254  
         /** Returns if a string shares at least a specified numbers starting characters with a number of matches.
 1255  
          * <p>
 1256  
          * This method just exercise {@link #startsWithLenient(String, String, int, boolean)} with every one of
 1257  
          * <code>matches</code> and <code>minChars</code>.
 1258  
          * @param s The string to check. Not <code>null</code>.
 1259  
          * @param matches A number of possible starts for <code>s</code>.
 1260  
          * @param minChars The minimum number of characters to match for every element in <code>matches</code>. Needs
 1261  
          * to be of same length as <code>matches</code>. Can be <code>null</code>.
 1262  
          * @param acceptTrailing If after the required number of characters are matched on recognized characters that are not
 1263  
          * in one of the the <code>matches</code> string should be accepted. For instance if "abczz" should be matched with
 1264  
          * "abcdef" and min chars 3.
 1265  
          * @return The index of the first unmatched character if <code>minChars</code> was reached or <code>-1</code> if a match was not
 1266  
          * found.
 1267  
          */
 1268  
         private static int startsWithLenient(String s, String[] matches, int[] minChars, boolean acceptTrailing)
 1269  
         {
 1270  
                 for (int i = 0; i < matches.length; i++) {
 1271  
                         int minChar = minChars != null ? minChars[i] : -1;
 1272  
                         int ix = startsWithLenient(s, matches[i], minChar, acceptTrailing);
 1273  
                         if (ix > -1)
 1274  
                                 return ix;
 1275  
                 }
 1276  
                 return -1;
 1277  
         }
 1278  
 
 1279  
         /** Returns if a string shares at least a specified numbers starting characters with a match.
 1280  
          * @param s The string to check. Not <code>null</code> and must be trimmed.
 1281  
          * @param match The possible start for <code>s</code>. Not <code>null</code> and must be trimmed.
 1282  
          * @param minChars The mimimum number of characters to match to <code>s</code> for it this to be considered a match. -1 means
 1283  
          * the full length of <code>match</code>.
 1284  
          * @param acceptTrailing If after the required number of charecters are matched unrecognized characters that are not
 1285  
          * in one of the the <code>matches</code> string should be accepted. For instance if "abczz" should be matched with
 1286  
          * "abcdef" and min chars 3.
 1287  
          * @return The index of the first unmatched character if <code>minChars</code> was reached or <code>-1</code> if a match was not
 1288  
          * found.
 1289  
          */
 1290  
         private static int startsWithLenient(String s, String match, int minChars, boolean acceptTrailing)
 1291  
         {
 1292  
                 if (s.charAt(0) != match.charAt(0)) // Fast sanity check.
 1293  
                         return -1;
 1294  
 
 1295  
                 if (minChars == -1)
 1296  
                         minChars = match.length();
 1297  
 
 1298  
                 int sSz = s.length();
 1299  
                 if (sSz < minChars)
 1300  
                         return -1;
 1301  
 
 1302  
                 int mSz = match.length();
 1303  
                 int sIx = 0;
 1304  
                 for (int mIx = 0; mIx < mSz; sIx++, mIx++) {
 1305  
                         while (sIx < sSz && (s.charAt(sIx) == ' ' || s.charAt(sIx) == '_'))    // Disregard spaces and _
 1306  
                                 sIx++;
 1307  
 
 1308  
                         if (sIx >= sSz || s.charAt(sIx) != match.charAt(mIx))
 1309  
                                 return mIx >= minChars && (acceptTrailing || sIx >= sSz) && (sIx >= sSz || s.charAt(sIx - 1) == ' ') ? sIx : -1;
 1310  
                 }
 1311  
                 return sIx >= sSz || acceptTrailing ||s.charAt(sIx) == ' ' ? sIx : -1;
 1312  
         }
 1313  
 
 1314  
         /** Parses a string and returns it in those parts of the string that are separated with a <code>sep</code> character.
 1315  
          * <p>
 1316  
          * separator characters within parentheses will not be counted or handled in any way, whatever the depth.
 1317  
          * <p>
 1318  
          * A space separator will be a hit to one or more spaces and thus not return empty strings.
 1319  
          * @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
 1320  
          * two <code>sep</code> are next to each other and empty element will be "between" the periods. The <code>sep</code> themselves will never be returned.
 1321  
          * @param sep The separator char.
 1322  
          * @return Those parts of the string that are separated with <code>sep</code>. Never null and at least of size 1
 1323  
          * @since 6.7.2 Changed so more than one space in a row works as one space.
 1324  
          */
 1325  
         private static String[] toTrimmedTokens(String s, char sep)
 1326  
         {
 1327  
                 int toks = 0, sSize = s.length();
 1328  
                 boolean disregardDoubles = sep == ' ';
 1329  
 
 1330  
                 // Count the sep:s
 1331  
                 int p = 0;
 1332  
                 for(int i = 0; i < sSize; i++) {
 1333  
                         char c = s.charAt(i);
 1334  
                         if (c == '(') {
 1335  
                                 p++;
 1336  
                         } else if (c == ')') {
 1337  
                                 p--;
 1338  
                         } else if (p == 0 && c == sep) {
 1339  
                                 toks++;
 1340  
                                 while (disregardDoubles && i < sSize - 1 && s.charAt(i + 1) == ' ')
 1341  
                                         i++;
 1342  
                         }
 1343  
                         if (p < 0)
 1344  
                                 throw new IllegalArgumentException("Unbalanced parentheses: '" + s + "'");
 1345  
                 }
 1346  
                 if (p != 0)
 1347  
                         throw new IllegalArgumentException("Unbalanced parentheses: '" + s + "'");
 1348  
 
 1349  
                 if (toks == 0)
 1350  
                         return new String [] {s.trim()};
 1351  
 
 1352  
                 String[] retArr = new String[toks + 1];
 1353  
 
 1354  
                 int st = 0, pNr = 0;
 1355  
                 p = 0;
 1356  
                 for (int i = 0; i < sSize; i++) {
 1357  
 
 1358  
                         char c = s.charAt(i);
 1359  
                         if (c == '(') {
 1360  
                                 p++;
 1361  
                         } else if (c == ')') {
 1362  
                                 p--;
 1363  
                         } else if (p == 0 && c == sep) {
 1364  
                                 retArr[pNr++] = s.substring(st, i).trim();
 1365  
                                 st = i + 1;
 1366  
                                 while (disregardDoubles && i < sSize - 1 && s.charAt(i + 1) == ' ')
 1367  
                                         i++;
 1368  
                         }
 1369  
                 }
 1370  
 
 1371  
                 retArr[pNr++] = s.substring(st, sSize).trim();
 1372  
                 return retArr;
 1373  
         }
 1374  
 
 1375  
         /** Parses "AAA[BBB]CCC[DDD]EEE" into {"AAA", "BBB", "CCC", "DDD", "EEE", "FFF"}. Handles empty parts. Will always start and end outside
 1376  
          * a [] block so that the number of returned elemets will always be uneven and at least of length 3.
 1377  
          * <p>
 1378  
          * "|" is interpreted as "][".
 1379  
          * @param s The string. Might be "" but not null. Should be trimmed.
 1380  
          * @return The string divided into elements. Never <code>null</code> and at least of length 3.
 1381  
          * @throws IllegalArgumentException If a [] mismatch of some kind. (If not same [ as ] count or if the interleave.)
 1382  
          */
 1383  
         private static ArrayList<String> getRowColAndGapsTrimmed(String s)
 1384  
         {
 1385  
                 if (s.indexOf('|') != -1)
 1386  
                         s = s.replaceAll("\\|", "][");
 1387  
 
 1388  
                 ArrayList<String> retList = new ArrayList<String>(Math.max(s.length() >> 2 + 1, 3)); // Approx return length.
 1389  
                 int s0 = 0, s1 = 0; // '[' and ']' count.
 1390  
                 int st = 0; // Start of "next token to add".
 1391  
                 for (int i = 0, iSz = s.length(); i < iSz; i++) {
 1392  
                         char c = s.charAt(i);
 1393  
                         if (c == '[') {
 1394  
                                 s0++;
 1395  
                         } else if (c == ']') {
 1396  
                                 s1++;
 1397  
                         } else {
 1398  
                                 continue;
 1399  
                         }
 1400  
 
 1401  
                         if (s0 != s1 && (s0 - 1) != s1)
 1402  
                                 break;  // Wrong [ or ] found. Break for throw.
 1403  
 
 1404  
                         retList.add(s.substring(st, i).trim());
 1405  
                         st = i + 1;
 1406  
                 }
 1407  
                 if (s0 != s1)
 1408  
                         throw new IllegalArgumentException("'[' and ']' mismatch in row/column format string: " + s);
 1409  
 
 1410  
                 if (s0 == 0) {
 1411  
                         retList.add("");
 1412  
                         retList.add(s);
 1413  
                         retList.add("");
 1414  
                 } else if (retList.size() % 2 == 0) {
 1415  
                         retList.add(s.substring(st, s.length()));
 1416  
                 }
 1417  
 
 1418  
                 return retList;
 1419  
         }
 1420  
 
 1421  
         /** Makes <code>null</code> "", trims and converts to lower case.
 1422  
          * @param s The string
 1423  
          * @return Not null.
 1424  
          */
 1425  
         public static String prepare(String s)
 1426  
         {
 1427  
                 return s != null ? s.trim().toLowerCase() : "";
 1428  
         }
 1429  
 
 1430  
 //        /** Tests to serialize and deserialize the object with both XMLEncoder/Decoder and through Serializable
 1431  
 //         * @param o The object to serialize
 1432  
 //         * @return The same object after a tri through the process.
 1433  
 //         */
 1434  
 //        public static final Object serializeTest(Object o)
 1435  
 //        {
 1436  
 //                try {
 1437  
 //                        ByteArrayOutputStream barr = new ByteArrayOutputStream();
 1438  
 //                        XMLEncoder enc = new XMLEncoder(barr);
 1439  
 //                        enc.writeObject(o);
 1440  
 //                        enc.close();
 1441  
 //
 1442  
 //                        XMLDecoder dec = new XMLDecoder(new ByteArrayInputStream(barr.toByteArray()));
 1443  
 //                        o = dec.readObject();
 1444  
 //                        dec.close();
 1445  
 //                } catch (Exception e) {
 1446  
 //                        e.printStackTrace();
 1447  
 //                }
 1448  
 //
 1449  
 //                try {
 1450  
 //                        ByteArrayOutputStream barr = new ByteArrayOutputStream();
 1451  
 //                        ObjectOutputStream oos = new ObjectOutputStream(barr);
 1452  
 //                        oos.writeObject(o);
 1453  
 //                        oos.close();
 1454  
 //
 1455  
 //                        ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(barr.toByteArray()));
 1456  
 //                        o = ois.readObject();
 1457  
 //                        ois.close();
 1458  
 //                } catch (Exception e) {
 1459  
 //                        e.printStackTrace();
 1460  
 //                }
 1461  
 //
 1462  
 //                return o;
 1463  
 //        }
 1464  
 }