1 package net.miginfocom.swing;
6 * Copyright (c) 2004, Mikael Grev, MiG InfoCom AB. (miglayout (at) miginfocom (dot) com)
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.
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
32 * @author Mikael Grev, MiG InfoCom AB
36 import java.awt.Component;
37 import java.awt.Container;
38 import java.awt.Dimension;
39 import java.awt.Insets;
40 import java.awt.LayoutManager;
41 import java.awt.LayoutManager2;
42 import java.awt.Point;
43 import java.awt.Window;
44 import java.awt.event.ActionEvent;
45 import java.awt.event.ActionListener;
46 import java.util.ArrayList;
47 import java.util.Arrays;
48 import java.util.HashMap;
49 import java.util.HashSet;
50 import java.util.IdentityHashMap;
51 import java.util.Iterator;
54 import javax.swing.BoxLayout;
55 import javax.swing.JComponent;
56 import javax.swing.JEditorPane;
57 import javax.swing.JPopupMenu;
58 import javax.swing.JTextArea;
59 import javax.swing.OverlayLayout;
60 import javax.swing.SwingUtilities;
61 import javax.swing.Timer;
63 import net.miginfocom.layout.AC;
64 import net.miginfocom.layout.BoundSize;
65 import net.miginfocom.layout.CC;
66 import net.miginfocom.layout.ComponentWrapper;
67 import net.miginfocom.layout.ConstraintParser;
68 import net.miginfocom.layout.ContainerWrapper;
69 import net.miginfocom.layout.Grid;
70 import net.miginfocom.layout.LC;
71 import net.miginfocom.layout.LayoutCallback;
72 import net.miginfocom.layout.LayoutUtil;
73 import net.miginfocom.layout.PlatformDefaults;
74 import net.miginfocom.layout.UnitValue;
76 /** A very flexible layout manager.
78 * Read the documentation that came with this layout manager for information on usage.
80 public class MigLayout implements LayoutManager2//, Externalizable
82 // ******** Instance part ********
84 /** The component to string constraints mappings.
86 private final Map<Component, Object> scrConstrMap = new IdentityHashMap<Component, Object>(8);
88 /** Hold the serializable text representation of the constraints.
90 private Object layoutConstraints = "", colConstraints = "", rowConstraints = ""; // Should never be null!
92 // ******** Transient part ********
94 private transient ContainerWrapper cacheParentW = null;
96 private transient final Map<ComponentWrapper, CC> ccMap = new HashMap<ComponentWrapper, CC>(8);
97 private transient javax.swing.Timer debugTimer = null;
99 private transient LC lc = null;
100 private transient AC colSpecs = null, rowSpecs = null;
101 private transient Grid grid = null;
102 private transient int lastModCount = PlatformDefaults.getModCount();
103 private transient int lastHash = -1;
104 private transient Dimension lastInvalidSize = null;
105 private transient boolean lastWasInvalid = false; // Added in 3.7.1. May have regressions
106 private transient Dimension lastParentSize = null;
108 private transient ArrayList<LayoutCallback> callbackList = null;
110 private transient boolean dirty = true;
112 /** Constructor with no constraints.
120 * @param layoutConstraints The constraints that concern the whole layout. <code>null</code> will be treated as "".
122 public MigLayout(String layoutConstraints)
124 this(layoutConstraints, "", "");
128 * @param layoutConstraints The constraints that concern the whole layout. <code>null</code> will be treated as "".
129 * @param colConstraints The constraints for the columns in the grid. <code>null</code> will be treated as "".
131 public MigLayout(String layoutConstraints, String colConstraints)
133 this(layoutConstraints, colConstraints, "");
137 * @param layoutConstraints The constraints that concern the whole layout. <code>null</code> will be treated as "".
138 * @param colConstraints The constraints for the columns in the grid. <code>null</code> will be treated as "".
139 * @param rowConstraints The constraints for the rows in the grid. <code>null</code> will be treated as "".
141 public MigLayout(String layoutConstraints, String colConstraints, String rowConstraints)
143 setLayoutConstraints(layoutConstraints);
144 setColumnConstraints(colConstraints);
145 setRowConstraints(rowConstraints);
149 * @param layoutConstraints The constraints that concern the whole layout. <code>null</code> will be treated as an empty constraint.
151 public MigLayout(LC layoutConstraints)
153 this(layoutConstraints, null, null);
157 * @param layoutConstraints The constraints that concern the whole layout. <code>null</code> will be treated as an empty constraint.
158 * @param colConstraints The constraints for the columns in the grid. <code>null</code> will be treated as an empty constraint.
160 public MigLayout(LC layoutConstraints, AC colConstraints)
162 this(layoutConstraints, colConstraints, null);
166 * @param layoutConstraints The constraints that concern the whole layout. <code>null</code> will be treated as an empty constraint.
167 * @param colConstraints The constraints for the columns in the grid. <code>null</code> will be treated as an empty constraint.
168 * @param rowConstraints The constraints for the rows in the grid. <code>null</code> will be treated as an empty constraint.
170 public MigLayout(LC layoutConstraints, AC colConstraints, AC rowConstraints)
172 setLayoutConstraints(layoutConstraints);
173 setColumnConstraints(colConstraints);
174 setRowConstraints(rowConstraints);
177 /** Returns layout constraints either as a <code>String</code> or {@link net.miginfocom.layout.LC} depending what was sent in
178 * to the constructor or set with {@link #setLayoutConstraints(Object)}.
179 * @return The layout constraints either as a <code>String</code> or {@link net.miginfocom.layout.LC} depending what was sent in
180 * to the constructor or set with {@link #setLayoutConstraints(Object)}. Never <code>null</code>.
182 public Object getLayoutConstraints()
184 return layoutConstraints;
187 /** Sets the layout constraints for the layout manager instance as a String.
189 * See the class JavaDocs for information on how this string is formatted.
190 * @param constr The layout constraints as a String or {@link net.miginfocom.layout.LC} representation. <code>null</code> is converted to <code>""</code> for storage.
191 * @throws RuntimeException if the constraint was not valid.
193 public void setLayoutConstraints(Object constr)
195 if (constr == null || constr instanceof String) {
196 constr = ConstraintParser.prepare((String) constr);
197 lc = ConstraintParser.parseLayoutConstraint((String) constr);
198 } else if (constr instanceof LC) {
201 throw new IllegalArgumentException("Illegal constraint type: " + constr.getClass().toString());
203 layoutConstraints = constr;
207 /** Returns the column layout constraints either as a <code>String</code> or {@link net.miginfocom.layout.AC}.
208 * @return The column constraints either as a <code>String</code> or {@link net.miginfocom.layout.AC} depending what was sent in
209 * to the constructor or set with {@link #setColumnConstraints(Object)}. Never <code>null</code>.
211 public Object getColumnConstraints()
213 return colConstraints;
216 /** Sets the column layout constraints for the layout manager instance as a String.
218 * See the class JavaDocs for information on how this string is formatted.
219 * @param constr The column layout constraints as a String or {@link net.miginfocom.layout.AC} representation. <code>null</code> is converted to <code>""</code> for storage.
220 * @throws RuntimeException if the constraint was not valid.
222 public void setColumnConstraints(Object constr)
224 if (constr == null || constr instanceof String) {
225 constr = ConstraintParser.prepare((String) constr);
226 colSpecs = ConstraintParser.parseColumnConstraints((String) constr);
227 } else if (constr instanceof AC) {
228 colSpecs = (AC) constr;
230 throw new IllegalArgumentException("Illegal constraint type: " + constr.getClass().toString());
232 colConstraints = constr;
236 /** Returns the row layout constraints either as a <code>String</code> or {@link net.miginfocom.layout.AC}.
237 * @return The row constraints either as a <code>String</code> or {@link net.miginfocom.layout.AC} depending what was sent in
238 * to the constructor or set with {@link #setRowConstraints(Object)}. Never <code>null</code>.
240 public Object getRowConstraints()
242 return rowConstraints;
245 /** Sets the row layout constraints for the layout manager instance as a String.
247 * See the class JavaDocs for information on how this string is formatted.
248 * @param constr The row layout constraints as a String or {@link net.miginfocom.layout.AC} representation. <code>null</code> is converted to <code>""</code> for storage.
249 * @throws RuntimeException if the constraint was not valid.
251 public void setRowConstraints(Object constr)
253 if (constr == null || constr instanceof String) {
254 constr = ConstraintParser.prepare((String) constr);
255 rowSpecs = ConstraintParser.parseRowConstraints((String) constr);
256 } else if (constr instanceof AC) {
257 rowSpecs = (AC) constr;
259 throw new IllegalArgumentException("Illegal constraint type: " + constr.getClass().toString());
261 rowConstraints = constr;
265 /** Returns a shallow copy of the constraints map.
266 * @return A shallow copy of the constraints map. Never <code>null</code>.
268 public Map<Component, Object> getConstraintMap()
270 return new IdentityHashMap<Component, Object>(scrConstrMap);
273 /** Sets the constraints map.
274 * @param map The map. Will be copied.
276 public void setConstraintMap(Map<Component, Object> map)
278 scrConstrMap.clear();
280 for (Map.Entry<Component, Object> e : map.entrySet())
281 setComponentConstraintsImpl(e.getKey(), e.getValue(), true);
284 /** Returns the component constraints as a String representation. This string is the exact string as set with {@link #setComponentConstraints(java.awt.Component, Object)}
285 * or set when adding the component to the parent component.
287 * See the class JavaDocs for information on how this string is formatted.
288 * @param comp The component to return the constraints for.
289 * @return The component constraints as a String representation or <code>null</code> if the component is not registered
290 * with this layout manager. The returned values is either a String or a {@link net.miginfocom.layout.CC}
291 * depending on what constraint was sent in when the component was added. May be <code>null</code>.
293 public Object getComponentConstraints(Component comp)
295 synchronized(comp.getParent().getTreeLock()) {
296 return scrConstrMap.get(comp);
300 /** Sets the component constraint for the component that already must be handled by this layout manager.
302 * See the class JavaDocs for information on how this string is formatted.
303 * @param constr The component constraints as a String or {@link net.miginfocom.layout.CC}. <code>null</code> is ok.
304 * @param comp The component to set the constraints for.
305 * @throws RuntimeException if the constraint was not valid.
306 * @throws IllegalArgumentException If the component is not handling the component.
308 public void setComponentConstraints(Component comp, Object constr)
310 setComponentConstraintsImpl(comp, constr, false);
313 /** Sets the component constraint for the component that already must be handled by this layout manager.
315 * See the class JavaDocs for information on how this string is formatted.
316 * @param constr The component constraints as a String or {@link net.miginfocom.layout.CC}. <code>null</code> is ok.
317 * @param comp The component to set the constraints for.
318 * @param noCheck Does not check if the component is handled if true
319 * @throws RuntimeException if the constraint was not valid.
320 * @throws IllegalArgumentException If the component is not handling the component.
322 private void setComponentConstraintsImpl(Component comp, Object constr, boolean noCheck)
324 Container parent = comp.getParent();
325 synchronized(parent != null ? parent.getTreeLock() : new Object()) { // 3.7.2. No sync if not added to a hierarchy. Defeats a NPE.
326 if (noCheck == false && scrConstrMap.containsKey(comp) == false)
327 throw new IllegalArgumentException("Component must already be added to parent!");
329 ComponentWrapper cw = new SwingComponentWrapper(comp);
331 if (constr == null || constr instanceof String) {
332 String cStr = ConstraintParser.prepare((String) constr);
334 scrConstrMap.put(comp, constr);
335 ccMap.put(cw, ConstraintParser.parseComponentConstraint(cStr));
337 } else if (constr instanceof CC) {
339 scrConstrMap.put(comp, constr);
340 ccMap.put(cw, (CC) constr);
343 throw new IllegalArgumentException("Constraint must be String or ComponentConstraint: " + constr.getClass().toString());
350 /** Returns if this layout manager is currently managing this component.
351 * @param c The component to check. If <code>null</code> then <code>false</code> will be returned.
352 * @return If this layout manager is currently managing this component.
354 public boolean isManagingComponent(Component c)
356 return scrConstrMap.containsKey(c);
359 /** Adds the callback function that will be called at different stages of the layout cycle.
360 * @param callback The callback. Not <code>null</code>.
362 public void addLayoutCallback(LayoutCallback callback)
364 if (callback == null)
365 throw new NullPointerException();
367 if (callbackList == null)
368 callbackList = new ArrayList<LayoutCallback>(1);
370 callbackList.add(callback);
375 /** Removes the callback if it exists.
376 * @param callback The callback. May be <code>null</code>.
378 public void removeLayoutCallback(LayoutCallback callback)
380 if (callbackList != null)
381 callbackList.remove(callback);
384 /** Sets the debugging state for this layout manager instance. If debug is turned on a timer will repaint the last laid out parent
385 * with debug information on top.
387 * Red fill and dashed red outline is used to indicate occupied cells in the grid. Blue dashed outline indicate
388 * component bounds set.
390 * Note that debug can also be set on the layout constraints. There it will be persisted. The value set here will not. See the class
391 * JavaDocs for information.
392 * @param parentW The parent to set debug for.
393 * @param b <code>true</code> means debug is turned on.
395 private void setDebug(final ComponentWrapper parentW, boolean b)
397 if (b && (debugTimer == null || debugTimer.getDelay() != getDebugMillis())) {
398 if (debugTimer != null)
401 ContainerWrapper pCW = parentW.getParent();
402 final Component parent = pCW != null ? (Component) pCW.getComponent() : null;
404 debugTimer = new Timer(getDebugMillis(), new MyDebugRepaintListener());
406 if (parent != null) {
407 SwingUtilities.invokeLater(new Runnable() {
410 Container p = parent.getParent();
412 if (p instanceof JComponent) {
413 ((JComponent) p).revalidate();
423 debugTimer.setInitialDelay(100);
426 } else if (!b && debugTimer != null) {
432 /** Returns the current debugging state.
433 * @return The current debugging state.
435 private boolean getDebug()
437 return debugTimer != null;
440 /** Returns the debug millis. Combines the value from {@link net.miginfocom.layout.LC#getDebugMillis()} and {@link net.miginfocom.layout.LayoutUtil#getGlobalDebugMillis()}
441 * @return The combined value.
443 private int getDebugMillis()
445 int globalDebugMillis = LayoutUtil.getGlobalDebugMillis();
446 return globalDebugMillis > 0 ? globalDebugMillis : lc.getDebugMillis();
449 /** Check if something has changed and if so recreate it to the cached objects.
450 * @param parent The parent that is the target for this layout manager.
452 private void checkCache(Container parent)
460 cleanConstraintMaps(parent);
462 // Check if the grid is valid
463 int mc = PlatformDefaults.getModCount();
464 if (lastModCount != mc) {
469 if (!parent.isValid()) {
470 if (!lastWasInvalid) {
471 lastWasInvalid = true;
474 boolean resetLastInvalidOnParent = false; // Added in 3.7.3 to resolve a timing regression introduced in 3.7.1
475 for (ComponentWrapper wrapper : ccMap.keySet()) {
476 Object component = wrapper.getComponent();
477 if (component instanceof JTextArea || component instanceof JEditorPane)
478 resetLastInvalidOnParent = true;
480 hash ^= wrapper.getLayoutHashCode();
483 if (resetLastInvalidOnParent)
484 resetLastInvalidOnParent(parent);
486 if (hash != lastHash) {
491 Dimension ps = parent.getSize();
492 if (lastInvalidSize == null || !lastInvalidSize.equals(ps)) {
494 lastInvalidSize = ps;
498 lastWasInvalid = false;
501 ContainerWrapper par = checkParent(parent);
503 setDebug(par, getDebugMillis() > 0);
506 grid = new Grid(par, lc, rowSpecs, colSpecs, ccMap, callbackList);
511 /** Checks so all components in ccMap actually exist in the parent's collection. Removes
512 * any references that don't.
513 * @param parent The parent to compare ccMap against. Never null.
515 private void cleanConstraintMaps(Container parent)
517 HashSet<Component> parentCompSet = new HashSet<Component>(Arrays.asList(parent.getComponents()));
519 Iterator<Map.Entry<ComponentWrapper, CC>> it = ccMap.entrySet().iterator();
520 while(it.hasNext()) {
521 Component c = (Component) it.next().getKey().getComponent();
522 if (parentCompSet.contains(c) == false) {
524 scrConstrMap.remove(c);
532 private void resetLastInvalidOnParent(Container parent)
534 while (parent != null) {
535 LayoutManager layoutManager = parent.getLayout();
536 if (layoutManager instanceof MigLayout) {
537 ((MigLayout) layoutManager).lastWasInvalid = false;
539 parent = parent.getParent();
543 private ContainerWrapper checkParent(Container parent)
548 if (cacheParentW == null || cacheParentW.getComponent() != parent)
549 cacheParentW = new SwingContainerWrapper(parent);
554 private long lastSize = 0;
557 public void layoutContainer(final Container parent)
559 synchronized(parent.getTreeLock()) {
562 Insets i = parent.getInsets();
563 int[] b = new int[] {
566 parent.getWidth() - i.left - i.right,
567 parent.getHeight() - i.top - i.bottom
570 if (grid.layout(b, lc.getAlignX(), lc.getAlignY(), getDebug())) {
573 grid.layout(b, lc.getAlignX(), lc.getAlignY(), getDebug());
576 long newSize = grid.getHeight()[1] + (((long) grid.getWidth()[1]) << 32);
577 if (lastSize != newSize) {
579 final ContainerWrapper containerWrapper = checkParent(parent);
580 Window win = ((Window) SwingUtilities.getAncestorOfClass(Window.class, (Component)containerWrapper.getComponent()));
582 if (win.isVisible()) {
583 SwingUtilities.invokeLater(new Runnable() {
586 adjustWindowSize(containerWrapper);
590 adjustWindowSize(containerWrapper);
594 lastInvalidSize = null;
598 /** Checks the parent window/popup if its size is within parameters as set by the LC.
599 * @param parent The parent who's window to possibly adjust the size for.
601 private void adjustWindowSize(ContainerWrapper parent)
603 BoundSize wBounds = lc.getPackWidth();
604 BoundSize hBounds = lc.getPackHeight();
606 if (wBounds == BoundSize.NULL_SIZE && hBounds == BoundSize.NULL_SIZE)
609 Container packable = getPackable((Component) parent.getComponent());
611 if (packable != null) {
613 Component pc = (Component) parent.getComponent();
615 Container c = pc instanceof Container ? (Container) pc : pc.getParent();
616 for (; c != null; c = c.getParent()) {
617 LayoutManager layout = c.getLayout();
618 if (layout instanceof BoxLayout || layout instanceof OverlayLayout)
619 ((LayoutManager2) layout).invalidateLayout(c);
622 Dimension prefSize = packable.getPreferredSize();
623 int targW = constrain(checkParent(packable), packable.getWidth(), prefSize.width, wBounds);
624 int targH = constrain(checkParent(packable), packable.getHeight(), prefSize.height, hBounds);
626 Point p = packable.isShowing() ? packable.getLocationOnScreen() : packable.getLocation();
628 int x = Math.round(p.x - ((targW - packable.getWidth()) * (1 - lc.getPackWidthAlign())));
629 int y = Math.round(p.y - ((targH - packable.getHeight()) * (1 - lc.getPackHeightAlign())));
631 if (packable instanceof JPopupMenu) {
632 JPopupMenu popupMenu = (JPopupMenu) packable;
633 popupMenu.setVisible(false);
634 popupMenu.setPopupSize(targW, targH);
635 Component invoker = popupMenu.getInvoker();
636 Point popPoint = new Point(x, y);
637 SwingUtilities.convertPointFromScreen(popPoint, invoker);
638 ((JPopupMenu) packable).show(invoker, popPoint.x, popPoint.y);
640 packable.setPreferredSize(null); // Reset preferred size so we don't read it again.
643 packable.setBounds(x, y, targW, targH);
648 /** Returns a high level window or popup to pack, if any.
649 * @return May be null.
651 private Container getPackable(Component comp)
653 JPopupMenu popup = findType(JPopupMenu.class, comp);
654 if (popup != null) { // Lightweight/HeavyWeight popup must be handled separately
655 Container popupComp = popup;
656 while (popupComp != null) {
657 if (popupComp.getClass().getName().contains("HeavyWeightWindow"))
658 return popupComp; // Return the heavy weight window for normal processing
659 popupComp = popupComp.getParent();
661 return popup; // Return the JPopup.
664 return findType(Window.class, comp);
667 public static <E> E findType(Class<E> clazz, Component comp)
669 while (comp != null && !clazz.isInstance(comp))
670 comp = comp.getParent();
676 private int constrain(ContainerWrapper parent, int winSize, int prefSize, BoundSize constrain)
678 if (constrain == null)
681 int retSize = winSize;
682 UnitValue wUV = constrain.getPreferred();
684 retSize = wUV.getPixels(prefSize, parent, parent);
686 retSize = constrain.constrain(retSize, prefSize, parent);
688 return constrain.getGapPush() ? Math.max(winSize, retSize) : retSize;
692 public Dimension minimumLayoutSize(Container parent)
694 synchronized(parent.getTreeLock()) {
695 return getSizeImpl(parent, LayoutUtil.MIN);
700 public Dimension preferredLayoutSize(Container parent)
702 synchronized(parent.getTreeLock()) {
703 if (lastParentSize == null || !parent.getSize().equals(lastParentSize)) {
704 for (ComponentWrapper wrapper : ccMap.keySet()) {
705 if (wrapper.getContentBias() != -1) {
706 layoutContainer(parent);
712 lastParentSize = parent.getSize();
713 return getSizeImpl(parent, LayoutUtil.PREF);
718 public Dimension maximumLayoutSize(Container parent)
720 return new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE);
723 // Implementation method that does the job.
724 private Dimension getSizeImpl(Container parent, int sizeType)
728 Insets i = parent.getInsets();
730 int w = LayoutUtil.getSizeSafe(grid != null ? grid.getWidth() : null, sizeType) + i.left + i.right;
731 int h = LayoutUtil.getSizeSafe(grid != null ? grid.getHeight() : null, sizeType) + i.top + i.bottom;
733 return new Dimension(w, h);
737 public float getLayoutAlignmentX(Container parent)
739 return lc != null && lc.getAlignX() != null ? lc.getAlignX().getPixels(1, checkParent(parent), null) : 0;
743 public float getLayoutAlignmentY(Container parent)
745 return lc != null && lc.getAlignY() != null ? lc.getAlignY().getPixels(1, checkParent(parent), null) : 0;
749 public void addLayoutComponent(String s, Component comp)
751 addLayoutComponent(comp, s);
755 public void addLayoutComponent(Component comp, Object constraints)
757 synchronized(comp.getParent().getTreeLock()) {
758 setComponentConstraintsImpl(comp, constraints, true);
763 public void removeLayoutComponent(Component comp)
765 synchronized(comp.getParent().getTreeLock()) {
766 scrConstrMap.remove(comp);
767 ccMap.remove(new SwingComponentWrapper(comp));
768 grid = null; // To clear references
773 public void invalidateLayout(Container target)
778 // // ************************************************
779 // // Persistence Delegate and Serializable combined.
780 // // ************************************************
782 // private Object readResolve() throws ObjectStreamException
784 // return LayoutUtil.getSerializedObject(this);
788 // public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException
790 // LayoutUtil.setSerializedObject(this, LayoutUtil.readAsXML(in));
794 // public void writeExternal(ObjectOutput out) throws IOException
796 // if (getClass() == MigLayout.class)
797 // LayoutUtil.writeAsXML(out, this);
800 private class MyDebugRepaintListener implements ActionListener
803 public void actionPerformed(ActionEvent e)
806 Component comp = (Component) grid.getContainer().getComponent();
807 if (comp.isShowing()) {