Source for javax.swing.OverlayLayout

   1: /* OverlayLayout.java -- A layout manager
   2:    Copyright (C) 2002, 2004, 2005, 2006, Free Software Foundation, Inc.
   3: 
   4: This file is part of GNU Classpath.
   5: 
   6: GNU Classpath is free software; you can redistribute it and/or modify
   7: it under the terms of the GNU General Public License as published by
   8: the Free Software Foundation; either version 2, or (at your option)
   9: any later version.
  10: 
  11: GNU Classpath is distributed in the hope that it will be useful, but
  12: WITHOUT ANY WARRANTY; without even the implied warranty of
  13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14: General Public License for more details.
  15: 
  16: You should have received a copy of the GNU General Public License
  17: along with GNU Classpath; see the file COPYING.  If not, write to the
  18: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  19: 02110-1301 USA.
  20: 
  21: Linking this library statically or dynamically with other modules is
  22: making a combined work based on this library.  Thus, the terms and
  23: conditions of the GNU General Public License cover the whole
  24: combination.
  25: 
  26: As a special exception, the copyright holders of this library give you
  27: permission to link this library with independent modules to produce an
  28: executable, regardless of the license terms of these independent
  29: modules, and to copy and distribute the resulting executable under
  30: terms of your choice, provided that you also meet, for each linked
  31: independent module, the terms and conditions of the license of that
  32: module.  An independent module is a module which is not derived from
  33: or based on this library.  If you modify this library, you may extend
  34: this exception to your version of the library, but you are not
  35: obligated to do so.  If you do not wish to do so, delete this
  36: exception statement from your version. */
  37: 
  38: package javax.swing;
  39: 
  40: import java.awt.AWTError;
  41: import java.awt.Component;
  42: import java.awt.Container;
  43: import java.awt.Dimension;
  44: import java.awt.Insets;
  45: import java.awt.LayoutManager2;
  46: import java.io.Serializable;
  47: 
  48: /**
  49:  * A layout manager that lays out the components of a container one over
  50:  * another.
  51:  *
  52:  * The components take as much space as is available in the container, but not
  53:  * more than specified by their maximum size.
  54:  *
  55:  * The overall layout is mainly affected by the components
  56:  * <code>alignmentX</code> and <code>alignmentY</code> properties. All
  57:  * components are aligned, so that their alignment points (for either
  58:  * direction) are placed in one line (the baseline for this direction).
  59:  *
  60:  * For example: An X alignment of 0.0 means that the component's alignment
  61:  * point is at it's left edge, an X alignment of 0.5 means that the alignment
  62:  * point is in the middle, an X alignment of 1.0 means, the aligment point is
  63:  * at the right edge. So if you have three components, the first with 0.0, the
  64:  * second with 0.5 and the third with 1.0, then they are laid out like this:
  65:  *
  66:  * <pre>
  67:  *          +-------+
  68:  *          |   1   |
  69:  *          +-------+
  70:  *      +-------+
  71:  *      |   2   |
  72:  *      +-------+
  73:  * +---------+
  74:  * |    3    +
  75:  * +---------+
  76:  * </pre>
  77:  * The above picture shows the X alignment between the components. An Y
  78:  * alignment like shown above cannot be achieved with this layout manager. The
  79:  * components are place on top of each other, with the X alignment shown above.
  80:  *
  81:  * @author Roman Kennke (kennke@aicas.com)
  82:  * @author Andrew Selkirk
  83:  */
  84: public class OverlayLayout implements LayoutManager2, Serializable
  85: {
  86:   private static final long serialVersionUID = 18082829169631543L;
  87: 
  88:   /**
  89:    * The container to be laid out.
  90:    */
  91:   private Container target;
  92: 
  93:   /**
  94:    * The size requirements of the containers children for the X direction.
  95:    */
  96:   private SizeRequirements[] xChildren;
  97: 
  98:   /**
  99:    * The size requirements of the containers children for the Y direction.
 100:    */
 101:   private SizeRequirements[] yChildren;
 102: 
 103:   /**
 104:    * The size requirements of the container to be laid out for the X direction.
 105:    */
 106:   private SizeRequirements xTotal;
 107: 
 108:   /**
 109:    * The size requirements of the container to be laid out for the Y direction.
 110:    */
 111:   private SizeRequirements yTotal;
 112: 
 113:   /**
 114:    * The offsets of the child components in the X direction.
 115:    */
 116:   private int[] offsetsX;
 117: 
 118:   /**
 119:    * The offsets of the child components in the Y direction.
 120:    */
 121:   private int[] offsetsY;
 122: 
 123:   /**
 124:    * The spans of the child components in the X direction.
 125:    */
 126:   private int[] spansX;
 127: 
 128:   /**
 129:    * The spans of the child components in the Y direction.
 130:    */
 131:   private int[] spansY;
 132: 
 133:   /**
 134:    * Creates a new OverlayLayout for the specified container.
 135:    *
 136:    * @param target the container to be laid out
 137:    */
 138:   public OverlayLayout(Container target)
 139:   {
 140:     this.target = target;
 141:   }
 142: 
 143:   /**
 144:    * Notifies the layout manager that the layout has become invalid. It throws
 145:    * away cached layout information and recomputes it the next time it is
 146:    * requested.
 147:    *
 148:    * @param target not used here
 149:    */
 150:   public void invalidateLayout(Container target)
 151:   {
 152:     xChildren = null;
 153:     yChildren = null;
 154:     xTotal = null;
 155:     yTotal = null;
 156:     offsetsX = null;
 157:     offsetsY = null;
 158:     spansX = null;
 159:     spansY = null;
 160:   }
 161: 
 162:   /**
 163:    * This method is not used in this layout manager.
 164:    *
 165:    * @param string not used here
 166:    * @param component not used here
 167:    */
 168:   public void addLayoutComponent(String string, Component component)
 169:   {
 170:     // Nothing to do here.
 171:   }
 172: 
 173:   /**
 174:    * This method is not used in this layout manager.
 175:    *
 176:    * @param component not used here
 177:    * @param constraints not used here
 178:    */
 179:   public void addLayoutComponent(Component component, Object constraints)
 180:   {
 181:     // Nothing to do here.
 182:   }
 183: 
 184:   /**
 185:    * This method is not used in this layout manager.
 186:    *
 187:    * @param component not used here
 188:    */
 189:   public void removeLayoutComponent(Component component)
 190:   {
 191:     // Nothing to do here.
 192:   }
 193: 
 194:   /**
 195:    * Returns the preferred size of the container that is laid out. This is
 196:    * computed by the children's preferred sizes, taking their alignments into
 197:    * account.
 198:    *
 199:    * @param target not used here
 200:    *
 201:    * @return the preferred size of the container that is laid out
 202:    */
 203:   public Dimension preferredLayoutSize(Container target)
 204:   {
 205:     if (target != this.target)
 206:       throw new AWTError("OverlayLayout can't be shared");
 207: 
 208:     checkTotalRequirements();
 209:     return new Dimension(xTotal.preferred, yTotal.preferred);
 210:   }
 211: 
 212:   /**
 213:    * Returns the minimum size of the container that is laid out. This is
 214:    * computed by the children's minimum sizes, taking their alignments into
 215:    * account.
 216:    *
 217:    * @param target not used here
 218:    *
 219:    * @return the minimum size of the container that is laid out
 220:    */
 221:   public Dimension minimumLayoutSize(Container target)
 222:   {
 223:     if (target != this.target)
 224:       throw new AWTError("OverlayLayout can't be shared");
 225: 
 226:     checkTotalRequirements();
 227:     return new Dimension(xTotal.minimum, yTotal.minimum);
 228:   }
 229: 
 230:   /**
 231:    * Returns the maximum size of the container that is laid out. This is
 232:    * computed by the children's maximum sizes, taking their alignments into
 233:    * account.
 234:    *
 235:    * @param target not used here
 236:    *
 237:    * @return the maximum size of the container that is laid out
 238:    */
 239:   public Dimension maximumLayoutSize(Container target)
 240:   {
 241:     if (target != this.target)
 242:       throw new AWTError("OverlayLayout can't be shared");
 243: 
 244:     checkTotalRequirements();
 245:     return new Dimension(xTotal.maximum, yTotal.maximum);
 246:   }
 247: 
 248:   /**
 249:    * Returns the X alignment of the container that is laid out. This is
 250:    * computed by the children's preferred sizes, taking their alignments into
 251:    * account.
 252:    *
 253:    * @param target not used here
 254:    *
 255:    * @return the X alignment of the container that is laid out
 256:    */
 257:   public float getLayoutAlignmentX(Container target)
 258:   {
 259:     if (target != this.target)
 260:       throw new AWTError("OverlayLayout can't be shared");
 261: 
 262:     checkTotalRequirements();
 263:     return xTotal.alignment;
 264:   }
 265: 
 266:   /**
 267:    * Returns the Y alignment of the container that is laid out. This is
 268:    * computed by the children's preferred sizes, taking their alignments into
 269:    * account.
 270:    *
 271:    * @param target not used here
 272:    *
 273:    * @return the X alignment of the container that is laid out
 274:    */
 275:   public float getLayoutAlignmentY(Container target)
 276:   {
 277:     if (target != this.target)
 278:       throw new AWTError("OverlayLayout can't be shared");
 279: 
 280:     checkTotalRequirements();
 281:     return yTotal.alignment;
 282:   }
 283: 
 284:   /**
 285:    * Lays out the container and it's children.
 286:    *
 287:    * The children are laid out one over another.
 288:    *
 289:    * The components take as much space as is available in the container, but
 290:    * not more than specified by their maximum size.
 291:    *
 292:    * The overall layout is mainly affected by the components
 293:    * <code>alignmentX</code> and <code>alignmentY</code> properties. All
 294:    * components are aligned, so that their alignment points (for either
 295:    * direction) are placed in one line (the baseline for this direction).
 296:    *
 297:    * For example: An X alignment of 0.0 means that the component's alignment
 298:    * point is at it's left edge, an X alignment of 0.5 means that the alignment
 299:    * point is in the middle, an X alignment of 1.0 means, the aligment point is
 300:    * at the right edge. So if you have three components, the first with 0.0,
 301:    * the second with 0.5 and the third with 1.0, then they are laid out like
 302:    * this:
 303:    *
 304:    * <pre>
 305:    *          +-------+
 306:    *          |   1   |
 307:    *          +-------+
 308:    *      +-------+
 309:    *      |   2   |
 310:    *      +-------+
 311:    * +---------+
 312:    * |    3    +
 313:    * +---------+
 314:    * </pre>
 315:    * The above picture shows the X alignment between the components. An Y
 316:    * alignment like shown above cannot be achieved with this layout manager.
 317:    * The components are place on top of each other, with the X alignment shown
 318:    * above.
 319:    *
 320:    * @param target not used here
 321:    */
 322:   public void layoutContainer(Container target)
 323:   {
 324:     if (target != this.target)
 325:       throw new AWTError("OverlayLayout can't be shared");
 326: 
 327:     checkLayout();
 328:     Component[] children = target.getComponents();
 329:     for (int i = 0; i < children.length; i++)
 330:       children[i].setBounds(offsetsX[i], offsetsY[i], spansX[i], spansY[i]);
 331:   }
 332: 
 333:   /**
 334:    * Makes sure that the xChildren and yChildren fields are correctly set up.
 335:    * A call to {@link #invalidateLayout(Container)} sets these fields to null,
 336:    * so they have to be set up again.
 337:    */
 338:   private void checkRequirements()
 339:   {
 340:     if (xChildren == null || yChildren == null)
 341:       {
 342:         Component[] children = target.getComponents();
 343:         xChildren = new SizeRequirements[children.length];
 344:         yChildren = new SizeRequirements[children.length];
 345:         for (int i = 0; i < children.length; i++)
 346:           {
 347:             if (! children[i].isVisible())
 348:               {
 349:                 xChildren[i] = new SizeRequirements();
 350:                 yChildren[i] = new SizeRequirements();
 351:               }
 352:             else
 353:               {
 354:                 xChildren[i] =
 355:                   new SizeRequirements(children[i].getMinimumSize().width,
 356:                                        children[i].getPreferredSize().width,
 357:                                        children[i].getMaximumSize().width,
 358:                                        children[i].getAlignmentX());
 359:                 yChildren[i] =
 360:                   new SizeRequirements(children[i].getMinimumSize().height,
 361:                                        children[i].getPreferredSize().height,
 362:                                        children[i].getMaximumSize().height,
 363:                                        children[i].getAlignmentY());
 364:               }
 365:           }
 366:       }
 367:   }
 368: 
 369:   /**
 370:    * Makes sure that the xTotal and yTotal fields are set up correctly. A call
 371:    * to {@link #invalidateLayout} sets these fields to null and they have to be
 372:    * recomputed.
 373:    */
 374:   private void checkTotalRequirements()
 375:   {
 376:     if (xTotal == null || yTotal == null)
 377:       {
 378:         checkRequirements();
 379:         xTotal = SizeRequirements.getAlignedSizeRequirements(xChildren);
 380:         yTotal = SizeRequirements.getAlignedSizeRequirements(yChildren);
 381:       }
 382:   }
 383: 
 384:   /**
 385:    * Makes sure that the offsetsX, offsetsY, spansX and spansY fields are set
 386:    * up correctly. A call to {@link #invalidateLayout} sets these fields
 387:    * to null and they have to be recomputed.
 388:    */
 389:   private void checkLayout()
 390:   {
 391:     if (offsetsX == null || offsetsY == null || spansX == null
 392:         || spansY == null)
 393:       {
 394:         checkRequirements();
 395:         checkTotalRequirements();
 396:         int len = target.getComponents().length;
 397:         offsetsX = new int[len];
 398:         offsetsY = new int[len];
 399:         spansX = new int[len];
 400:         spansY = new int[len];
 401: 
 402:         Insets in = target.getInsets();
 403:         int width = target.getWidth() - in.left - in.right;
 404:         int height = target.getHeight() - in.top - in.bottom;
 405: 
 406:         SizeRequirements.calculateAlignedPositions(width, xTotal,
 407:                                                    xChildren, offsetsX, spansX);
 408:         SizeRequirements.calculateAlignedPositions(height, yTotal,
 409:                                                    yChildren, offsetsY, spansY);
 410:       }
 411:   }
 412: }