MigInfo.com layout fixe (again?) libjs rebuilt
[jalview.git] / srcjar / net / miginfocom / layout / UnitValue.java
1 package net.miginfocom.layout;
2 /*
3  * License (BSD):
4  * ==============
5  *
6  * Copyright (c) 2004, Mikael Grev, MiG InfoCom AB. (miglayout (at) miginfocom (dot) com)
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without modification,
10  * are permitted provided that the following conditions are met:
11  * Redistributions of source code must retain the above copyright notice, this list
12  * of conditions and the following disclaimer.
13  * Redistributions in binary form must reproduce the above copyright notice, this
14  * list of conditions and the following disclaimer in the documentation and/or other
15  * materials provided with the distribution.
16  * Neither the name of the MiG InfoCom AB nor the names of its contributors may be
17  * used to endorse or promote products derived from this software without specific
18  * prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
22  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23  * IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
24  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
25  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
26  * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
27  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
29  * OF SUCH DAMAGE.
30  *
31  * @version 1.0
32  * @author Mikael Grev, MiG InfoCom AB
33  *         Date: 2006-sep-08
34  */
35
36 import java.beans.Encoder;
37 import java.beans.Expression;
38 import java.beans.PersistenceDelegate;
39 import java.io.*;
40 import java.util.ArrayList;
41 import java.util.HashMap;
42
43 public final class UnitValue implements Serializable
44 {
45         private static final HashMap<String, Integer> UNIT_MAP = new HashMap<String, Integer>(32);
46
47         private static final ArrayList<UnitConverter> CONVERTERS = new ArrayList<UnitConverter>();
48
49         /** An operation indicating a static value.
50          */
51         public static final int STATIC = 100;
52
53         /** An operation indicating a addition of two sub units.
54          */
55         public static final int ADD = 101; // Must have "sub-unit values"
56
57         /** An operation indicating a subtraction of two sub units
58          */
59         public static final int SUB = 102; // Must have "sub-unit values"
60
61         /** An operation indicating a multiplication of two sub units.
62          */
63         public static final int MUL = 103; // Must have "sub-unit values"
64
65         /** An operation indicating a division of two sub units.
66          */
67         public static final int DIV = 104; // Must have "sub-unit values"
68
69         /** An operation indicating the minimum of two sub units
70          */
71         public static final int MIN = 105; // Must have "sub-unit values"
72
73         /** An operation indicating the maximum of two sub units
74          */
75         public static final int MAX = 106; // Must have "sub-unit values"
76
77         /** An operation indicating the middle value of two sub units
78          */
79         public static final int MID = 107; // Must have "sub-unit values"
80
81
82
83
84         /** A unit indicating pixels.
85          */
86         public static final int PIXEL = 0;
87
88         /** A unit indicating logical horizontal pixels.
89          */
90         public static final int LPX = 1;
91
92         /** A unit indicating logical vertical pixels.
93          */
94         public static final int LPY = 2;
95
96         /** A unit indicating millimeters.
97          */
98         public static final int MM = 3;
99
100         /** A unit indicating centimeters.
101          */
102         public static final int CM = 4;
103
104         /** A unit indicating inches.
105          */
106         public static final int INCH = 5;
107
108         /** A unit indicating percent.
109          */
110         public static final int PERCENT = 6;
111
112         /** A unit indicating points.
113          */
114         public static final int PT = 7;
115
116         /** A unit indicating screen percentage width.
117          */
118         public static final int SPX = 8;
119
120         /** A unit indicating screen percentage height.
121          */
122         public static final int SPY = 9;
123
124         /** A unit indicating alignment.
125          */
126         public static final int ALIGN = 12;
127
128         /** A unit indicating minimum size.
129          */
130         public static final int MIN_SIZE = 13;
131
132         /** A unit indicating preferred size.
133          */
134         public static final int PREF_SIZE = 14;
135
136         /** A unit indicating maximum size.
137          */
138         public static final int MAX_SIZE = 15;
139
140         /** A unit indicating button size.
141          */
142         public static final int BUTTON = 16;
143
144         /** A unit indicating linking to x.
145          */
146         public static final int LINK_X = 18;   // First link
147
148         /** A unit indicating linking to y.
149          */
150         public static final int LINK_Y = 19;
151
152         /** A unit indicating linking to width.
153          */
154         public static final int LINK_W = 20;
155
156         /** A unit indicating linking to height.
157          */
158         public static final int LINK_H = 21;
159
160         /** A unit indicating linking to x2.
161          */
162         public static final int LINK_X2 = 22;
163
164         /** A unit indicating linking to y2.
165          */
166         public static final int LINK_Y2 = 23;
167
168         /** A unit indicating linking to x position on screen.
169          */
170         public static final int LINK_XPOS = 24;
171
172         /** A unit indicating linking to y position on screen.
173          */
174         public static final int LINK_YPOS = 25;    // Last link
175
176         /** A unit indicating a lookup.
177          */
178         public static final int LOOKUP = 26;
179
180         /** A unit indicating label alignment.
181          */
182         public static final int LABEL_ALIGN = 27;
183
184         private static final int IDENTITY = -1;
185
186         static {
187                 UNIT_MAP.put("px", PIXEL);
188                 UNIT_MAP.put("lpx", LPX);
189                 UNIT_MAP.put("lpy", LPY);
190                 UNIT_MAP.put("%", PERCENT);
191                 UNIT_MAP.put("cm", CM);
192                 UNIT_MAP.put("in", INCH);
193                 UNIT_MAP.put("spx", SPX);
194                 UNIT_MAP.put("spy", SPY);
195                 UNIT_MAP.put("al", ALIGN);
196                 UNIT_MAP.put("mm", MM);
197                 UNIT_MAP.put("pt", PT);
198                 UNIT_MAP.put("min", MIN_SIZE);
199                 UNIT_MAP.put("minimum", MIN_SIZE);
200                 UNIT_MAP.put("p", PREF_SIZE);
201                 UNIT_MAP.put("pref", PREF_SIZE);
202                 UNIT_MAP.put("max", MAX_SIZE);
203                 UNIT_MAP.put("maximum", MAX_SIZE);
204                 UNIT_MAP.put("button", BUTTON);
205                 UNIT_MAP.put("label", LABEL_ALIGN);
206         }
207
208         static final UnitValue ZERO = new UnitValue(0, null, PIXEL, true, STATIC, null, null, "0px");
209         static final UnitValue TOP = new UnitValue(0, null, PERCENT, false, STATIC, null, null, "top");
210         static final UnitValue LEADING = new UnitValue(0, null, PERCENT, true, STATIC, null, null, "leading");
211         static final UnitValue LEFT = new UnitValue(0, null, PERCENT, true, STATIC, null, null, "left");
212         static final UnitValue CENTER = new UnitValue(50, null, PERCENT, true, STATIC, null, null, "center");
213         static final UnitValue TRAILING = new UnitValue(100, null, PERCENT, true, STATIC, null, null, "trailing");
214         static final UnitValue RIGHT = new UnitValue(100, null, PERCENT, true, STATIC, null, null, "right");
215         static final UnitValue BOTTOM = new UnitValue(100, null, PERCENT, false, STATIC, null, null, "bottom");
216         static final UnitValue LABEL = new UnitValue(0, null, LABEL_ALIGN, false, STATIC, null, null, "label");
217
218         static final UnitValue INF = new UnitValue(LayoutUtil.INF, null, PIXEL, true, STATIC, null, null, "inf");
219
220         static final UnitValue BASELINE_IDENTITY = new UnitValue(0, null, IDENTITY, false, STATIC, null, null, "baseline");
221
222         private final transient float value;
223         private final transient int unit;
224         private final transient int oper;
225         private final transient String unitStr;
226         private transient String linkId = null; // Should be final, but initializes in a sub method.
227         private final transient boolean isHor;
228         private final transient UnitValue[] subUnits;
229
230         // Pixel
231         public UnitValue(float value)  // If hor/ver does not matter.
232         {
233                 this(value, null, PIXEL, true, STATIC, null, null, value + "px");
234         }
235
236         public UnitValue(float value, int unit, String createString)  // If hor/ver does not matter.
237         {
238                 this(value, null, unit, true, STATIC, null, null, createString);
239         }
240
241         public UnitValue(float value, String unitStr, boolean isHor, int oper, String createString)
242         {
243                 this(value, unitStr, -1, isHor, oper, null, null, createString);
244         }
245
246         UnitValue(boolean isHor, int oper, UnitValue sub1, UnitValue sub2, String createString)
247         {
248                 this(0, "", -1, isHor, oper, sub1, sub2, createString);
249                 if (sub1 == null || sub2 == null)
250                         throw new IllegalArgumentException("Sub units is null!");
251         }
252
253         private UnitValue(float value, String unitStr, int unit, boolean isHor, int oper, UnitValue sub1, UnitValue sub2, String createString)
254         {
255                 if (oper < STATIC || oper > MID)
256                         throw new IllegalArgumentException("Unknown Operation: " + oper);
257
258                 if (oper >= ADD && oper <= MID && (sub1 == null || sub2 == null))
259                         throw new IllegalArgumentException(oper + " Operation may not have null sub-UnitValues.");
260
261                 this.value = value;
262                 this.oper = oper;
263                 this.isHor = isHor;
264                 this.unitStr = unitStr;
265                 this.unit = unitStr != null ? parseUnitString() : unit;
266                 this.subUnits = sub1 != null && sub2 != null ? new UnitValue[] {sub1, sub2} : null;
267
268                 LayoutUtil.putCCString(this, createString);    // "this" escapes!! Safe though.
269         }
270
271         /** Returns the size in pixels rounded.
272          * @param refValue The reference value. Normally the size of the parent. For unit {@link #ALIGN} the current size of the component should be sent in.
273          * @param parent The parent. May be <code>null</code> for testing the validity of the value, but should normally not and are not
274          * required to return any usable value if <code>null</code>.
275          * @param comp The component, if any, that the value is for. Might be <code>null</code> if the value is not
276          * connected to any component.
277          * @return The size in pixels.
278          */
279         public final int getPixels(float refValue, ContainerWrapper parent, ComponentWrapper comp)
280         {
281                 return Math.round(getPixelsExact(refValue, parent, comp));
282         }
283
284         private static final float[] SCALE = new float[] {25.4f, 2.54f, 1f, 0f, 72f};
285         /** Returns the size in pixels.
286          * @param refValue The reference value. Normally the size of the parent. For unit {@link #ALIGN} the current size of the component should be sent in.
287          * @param parent The parent. May be <code>null</code> for testing the validity of the value, but should normally not and are not
288          * required to return any usable value if <code>null</code>.
289          * @param comp The component, if any, that the value is for. Might be <code>null</code> if the value is not
290          * connected to any component.
291          * @return The size in pixels.
292          */
293         public final float getPixelsExact(float refValue, ContainerWrapper parent, ComponentWrapper comp)
294         {
295                 if (parent == null)
296                         return 1;
297
298                 if (oper == STATIC) {
299                         switch (unit) {
300                                 case PIXEL:
301                                         return value;
302
303                                 case LPX:
304                                 case LPY:
305                                         return parent.getPixelUnitFactor(unit == LPX) * value;
306
307                                 case MM:
308                                 case CM:
309                                 case INCH:
310                                 case PT:
311                                         float f = SCALE[unit - MM];
312                                         Float s = isHor ? PlatformDefaults.getHorizontalScaleFactor() : PlatformDefaults.getVerticalScaleFactor();
313                                         if (s != null)
314                                                 f *= s;
315
316                                         return (isHor ? parent.getHorizontalScreenDPI() : parent.getVerticalScreenDPI()) * value / f;
317
318                                 case PERCENT:
319                                         return value * refValue * 0.01f;
320
321                                 case SPX:
322                                 case SPY:
323                                         return (unit == SPX ? parent.getScreenWidth() : parent.getScreenHeight()) * value * 0.01f;
324
325                                 case ALIGN:
326                                         Integer st = LinkHandler.getValue(parent.getLayout(), "visual", isHor ? LinkHandler.X : LinkHandler.Y);
327                                         Integer sz = LinkHandler.getValue(parent.getLayout(), "visual", isHor ? LinkHandler.WIDTH : LinkHandler.HEIGHT);
328                                         if (st == null || sz == null)
329                                                 return 0;
330                                         return value * (Math.max(0, sz.intValue()) - refValue) + st;
331
332                                 case MIN_SIZE:
333                                         if (comp == null)
334                                                 return 0;
335                                         return isHor ? comp.getMinimumWidth(comp.getHeight()) : comp.getMinimumHeight(comp.getWidth());
336
337                                 case PREF_SIZE:
338                                         if (comp == null)
339                                                 return 0;
340                                         return isHor ? comp.getPreferredWidth(comp.getHeight()) : comp.getPreferredHeight(comp.getWidth());
341
342                                 case MAX_SIZE:
343                                         if (comp == null)
344                                                 return 0;
345                                         return isHor ? comp.getMaximumWidth(comp.getHeight()) : comp.getMaximumHeight(comp.getWidth());
346
347                                 case BUTTON:
348                                         return PlatformDefaults.getMinimumButtonWidthIncludingPadding(refValue, parent, comp);
349
350                                 case LINK_X:
351                                 case LINK_Y:
352                                 case LINK_W:
353                                 case LINK_H:
354                                 case LINK_X2:
355                                 case LINK_Y2:
356                                 case LINK_XPOS:
357                                 case LINK_YPOS:
358                                         Integer v = LinkHandler.getValue(parent.getLayout(), getLinkTargetId(), unit - (unit >= LINK_XPOS ? LINK_XPOS : LINK_X));
359                                         if (v == null)
360                                                 return 0;
361
362                                         if (unit == LINK_XPOS)
363                                                 return parent.getScreenLocationX() + v;
364                                         if (unit == LINK_YPOS)
365                                                 return parent.getScreenLocationY() + v;
366
367                                         return v;
368
369                                 case LOOKUP:
370                                         float res = lookup(refValue, parent, comp);
371                                         if (res != UnitConverter.UNABLE)
372                                                 return res;
373
374                                 case LABEL_ALIGN:
375                                         return PlatformDefaults.getLabelAlignPercentage() * refValue;
376
377                                 case IDENTITY:
378                         }
379                         throw new IllegalArgumentException("Unknown/illegal unit: " + unit + ", unitStr: " + unitStr);
380                 }
381
382                 if (subUnits != null && subUnits.length == 2) {
383                         float r1 = subUnits[0].getPixelsExact(refValue, parent, comp);
384                         float r2 = subUnits[1].getPixelsExact(refValue, parent, comp);
385                         switch (oper) {
386                                 case ADD:
387                                         return r1 + r2;
388                                 case SUB:
389                                         return r1 - r2;
390                                 case MUL:
391                                         return r1 * r2;
392                                 case DIV:
393                                         return r1 / r2;
394                                 case MIN:
395                                         return r1 < r2 ? r1 : r2;
396                                 case MAX:
397                                         return r1 > r2 ? r1 : r2;
398                                 case MID:
399                                         return (r1 + r2) * 0.5f;
400                         }
401                 }
402
403                 throw new IllegalArgumentException("Internal: Unknown Oper: " + oper);
404         }
405
406         private float lookup(float refValue, ContainerWrapper parent, ComponentWrapper comp)
407         {
408                 float res = UnitConverter.UNABLE;
409                 for (int i = CONVERTERS.size() - 1; i >= 0; i--) {
410                         res = CONVERTERS.get(i).convertToPixels(value, unitStr, isHor, refValue, parent, comp);
411                         if (res != UnitConverter.UNABLE)
412                                 return res;
413                 }
414                 return PlatformDefaults.convertToPixels(value, unitStr, isHor, refValue, parent, comp);
415         }
416
417         private int parseUnitString()
418         {
419                 int len = unitStr.length();
420                 if (len == 0)
421                         return isHor ? PlatformDefaults.getDefaultHorizontalUnit() : PlatformDefaults.getDefaultVerticalUnit();
422
423                 Integer u = UNIT_MAP.get(unitStr);
424                 if (u != null) {
425                         if (!isHor && (u == BUTTON || u == LABEL_ALIGN))
426                                 throw new IllegalArgumentException("Not valid in vertical contexts: '" + unitStr + "'");
427
428                         return u;
429                 }
430
431                 if (unitStr.equals("lp"))
432                         return isHor ? LPX : LPY;
433
434                 if (unitStr.equals("sp"))
435                         return isHor ? SPX : SPY;
436
437                 if (lookup(0, null, null) != UnitConverter.UNABLE)    // To test so we can fail fast
438                         return LOOKUP;
439
440                 // Only link left. E.g. "otherID.width"
441
442                 int pIx = unitStr.indexOf('.');
443                 if (pIx != -1) {
444                         linkId = unitStr.substring(0, pIx);
445                         String e = unitStr.substring(pIx + 1);
446
447                         if (e.equals("x"))
448                                 return LINK_X;
449                         if (e.equals("y"))
450                                 return LINK_Y;
451                         if (e.equals("w") || e.equals("width"))
452                                 return LINK_W;
453                         if (e.equals("h") || e.equals("height"))
454                                 return LINK_H;
455                         if (e.equals("x2"))
456                                 return LINK_X2;
457                         if (e.equals("y2"))
458                                 return LINK_Y2;
459                         if (e.equals("xpos"))
460                                 return LINK_XPOS;
461                         if (e.equals("ypos"))
462                                 return LINK_YPOS;
463                 }
464
465                 throw new IllegalArgumentException("Unknown keyword: " + unitStr);
466         }
467
468         final boolean isAbsolute()
469         {
470                 switch (unit) {
471                         case PIXEL:
472                         case LPX:
473                         case LPY:
474                         case MM:
475                         case CM:
476                         case INCH:
477                         case PT:
478                                 return true;
479
480                         case SPX:
481                         case SPY:
482                         case PERCENT:
483                         case ALIGN:
484                         case MIN_SIZE:
485                         case PREF_SIZE:
486                         case MAX_SIZE:
487                         case BUTTON:
488                         case LINK_X:
489                         case LINK_Y:
490                         case LINK_W:
491                         case LINK_H:
492                         case LINK_X2:
493                         case LINK_Y2:
494                         case LINK_XPOS:
495                         case LINK_YPOS:
496                         case LOOKUP:
497                         case LABEL_ALIGN:
498                                 return false;
499
500                         case IDENTITY:
501                 }
502                 throw new IllegalArgumentException("Unknown/illegal unit: " + unit + ", unitStr: " + unitStr);
503         }
504
505         final boolean isAbsoluteDeep()
506         {
507                 if (subUnits != null) {
508                         for (UnitValue subUnit : subUnits) {
509                                 if (subUnit.isAbsoluteDeep())
510                                         return true;
511                         }
512                 }
513                 return isAbsolute();
514         }
515
516         final boolean isLinked()
517         {
518                 return linkId != null;
519         }
520
521         final boolean isLinkedDeep()
522         {
523                 if (subUnits != null) {
524                         for (UnitValue subUnit : subUnits) {
525                                 if (subUnit.isLinkedDeep())
526                                         return true;
527                         }
528                 }
529                 return isLinked();
530         }
531
532         final String getLinkTargetId()
533         {
534                 return linkId;
535         }
536
537         final UnitValue getSubUnitValue(int i)
538         {
539                 return subUnits[i];
540         }
541
542         final int getSubUnitCount()
543         {
544                 return subUnits != null ? subUnits.length : 0;
545         }
546
547         public final UnitValue[] getSubUnits()
548         {
549                 return subUnits != null ? subUnits.clone() : null;
550         }
551
552         public final int getUnit()
553         {
554                 return unit;
555         }
556
557         public final String getUnitString()
558         {
559                 return unitStr;
560         }
561
562         public final int getOperation()
563         {
564                 return oper;
565         }
566
567         public final float getValue()
568         {
569                 return value;
570         }
571
572         public final boolean isHorizontal()
573         {
574                 return isHor;
575         }
576
577         @Override
578         final public String toString()
579         {
580                 return getClass().getName() + ". Value=" + value + ", unit=" + unit + ", unitString: " + unitStr + ", oper=" + oper + ", isHor: " + isHor;
581         }
582
583         /** Returns the creation string for this object. Note that {@link LayoutUtil#setDesignTime(ContainerWrapper, boolean)} must be
584          * set to <code>true</code> for the creation strings to be stored.
585          * @return The constraint string or <code>null</code> if none is registered.
586          */
587         public final String getConstraintString()
588         {
589                 return LayoutUtil.getCCString(this);
590         }
591
592         @Override
593         public final int hashCode()
594         {
595                 return (int) (value * 12345) + (oper >>> 5) + unit >>> 17;
596         }
597
598         /** Adds a global unit converter that can convert from some <code>unit</code> to pixels.
599          * <p>
600          * This converter will be asked before the platform converter so the values for it (e.g. "related" and "unrelated")
601          * can be overridden. It is however not possible to override the built in ones (e.g. "mm", "pixel" or "lp").
602          * @param conv The converter. Not <code>null</code>.
603          */
604         public synchronized static void addGlobalUnitConverter(UnitConverter conv)
605         {
606                 if (conv == null)
607                         throw new NullPointerException();
608                 CONVERTERS.add(conv);
609         }
610
611         /** Removed the converter.
612          * @param unit The converter.
613          * @return If there was a converter found and thus removed.
614          */
615         public synchronized static boolean removeGlobalUnitConverter(UnitConverter unit)
616         {
617                 return CONVERTERS.remove(unit);
618         }
619
620         /** Returns the global converters currently registered. The platform converter will not be in this list.
621          * @return The converters. Never <code>null</code>.
622          */
623         public synchronized static UnitConverter[] getGlobalUnitConverters()
624         {
625                 return CONVERTERS.toArray(new UnitConverter[CONVERTERS.size()]);
626         }
627
628         /** Returns the current default unit. The default unit is the unit used if no unit is set. E.g. "width 10".
629          * @return The current default unit.
630          * @see #PIXEL
631          * @see #LPX
632          * @deprecated Use {@link PlatformDefaults#getDefaultHorizontalUnit()} and {@link PlatformDefaults#getDefaultVerticalUnit()} instead.
633          */
634         public static int getDefaultUnit()
635         {
636                 return PlatformDefaults.getDefaultHorizontalUnit();
637         }
638
639         /** Sets the default unit. The default unit is the unit used if no unit is set. E.g. "width 10".
640          * @param unit The new default unit.
641          * @see #PIXEL
642          * @see #LPX
643          * @deprecated Use {@link PlatformDefaults#setDefaultHorizontalUnit(int)} and {@link PlatformDefaults#setDefaultVerticalUnit(int)} instead.
644          */
645         public static void setDefaultUnit(int unit)
646         {
647                 PlatformDefaults.setDefaultHorizontalUnit(unit);
648                 PlatformDefaults.setDefaultVerticalUnit(unit);
649         }
650
651 //      static {
652 //        if(LayoutUtil.HAS_BEANS){
653 //            LayoutUtil.setDelegate(UnitValue.class, new PersistenceDelegate() {
654 //                @Override
655 //                protected Expression instantiate(Object oldInstance, Encoder out)
656 //                {
657 //                    UnitValue uv = (UnitValue) oldInstance;
658 //                    String cs = uv.getConstraintString();
659 //                    if (cs == null)
660 //                        throw new IllegalStateException("Design time must be on to use XML persistence. See LayoutUtil.");
661 //
662 //                    return new Expression(oldInstance, ConstraintParser.class, "parseUnitValueOrAlign", new Object[] {
663 //                            uv.getConstraintString(), (uv.isHorizontal() ? Boolean.TRUE : Boolean.FALSE), null
664 //                    });
665 //                }
666 //            });
667 //        }
668 //      }
669
670         // ************************************************
671         // Persistence Delegate and Serializable combined.
672         // ************************************************
673
674         private static final long serialVersionUID = 1L;
675
676         private Object readResolve() throws ObjectStreamException
677         {
678                 return LayoutUtil.getSerializedObject(this);
679         }
680
681         private void writeObject(ObjectOutputStream out) throws IOException
682         {
683                 if (getClass() == UnitValue.class)
684                         LayoutUtil.writeAsXML(out, this);
685         }
686
687         private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException
688         {
689                 LayoutUtil.setSerializedObject(this, LayoutUtil.readAsXML(in));
690         }
691 }