Source for javax.swing.ScrollPaneLayout

   1: /* ScrollPaneLayout.java --
   2:    Copyright (C) 2002, 2004  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: 
  39: package javax.swing;
  40: 
  41: import java.awt.Component;
  42: import java.awt.Container;
  43: import java.awt.Dimension;
  44: import java.awt.Insets;
  45: import java.awt.LayoutManager;
  46: import java.awt.Rectangle;
  47: import java.io.Serializable;
  48: 
  49: import javax.swing.border.Border;
  50: 
  51: /**
  52:  * ScrollPaneLayout
  53:  * @author    Andrew Selkirk
  54:  * @version    1.0
  55:  */
  56: public class ScrollPaneLayout
  57:   implements LayoutManager, ScrollPaneConstants, Serializable
  58: {
  59:   private static final long serialVersionUID = -4480022884523193743L;
  60: 
  61:   public static class UIResource extends ScrollPaneLayout 
  62:     implements javax.swing.plaf.UIResource
  63:   {
  64:     public UIResource()
  65:     {
  66:       super();
  67:     }
  68:   }
  69: 
  70:   protected JViewport viewport;
  71:   protected JScrollBar vsb;
  72:   protected JScrollBar hsb;
  73:   protected JViewport rowHead;
  74:   protected JViewport colHead;
  75:   protected Component lowerLeft;
  76:   protected Component lowerRight;
  77:   protected Component upperLeft;
  78:   protected Component upperRight;
  79:   protected int vsbPolicy;
  80:   protected int hsbPolicy;
  81: 
  82:   public ScrollPaneLayout()
  83:   {
  84:     // Nothing to do here.
  85:   }
  86: 
  87:   public void syncWithScrollPane(JScrollPane scrollPane) 
  88:   {
  89:     viewport = scrollPane.getViewport();
  90:     rowHead = scrollPane.getRowHeader();
  91:     colHead = scrollPane.getColumnHeader();
  92:     vsb = scrollPane.getVerticalScrollBar();
  93:     hsb = scrollPane.getHorizontalScrollBar();
  94:     vsbPolicy = scrollPane.getVerticalScrollBarPolicy();
  95:     hsbPolicy = scrollPane.getHorizontalScrollBarPolicy();
  96:     lowerLeft = scrollPane.getCorner(LOWER_LEFT_CORNER);
  97:     lowerRight = scrollPane.getCorner(LOWER_RIGHT_CORNER);
  98:     upperLeft = scrollPane.getCorner(UPPER_LEFT_CORNER);
  99:     upperRight = scrollPane.getCorner(UPPER_RIGHT_CORNER);    
 100:   }
 101: 
 102:   /**
 103:    * Removes an existing component.  If oldComponent is not null
 104:    * and is not equal to newComponent, oldComponent must be removed
 105:    * from its parent.
 106:    * @param oldComponent the old Component that may need to be removed.
 107:    * @param newComponent the Component to add.
 108:    * @return the newComponent
 109:    */
 110:   protected Component addSingletonComponent(Component oldComponent,
 111:                                             Component newComponent) 
 112:   {
 113:     if (oldComponent != null && oldComponent != newComponent)
 114:       oldComponent.getParent().remove(oldComponent);
 115:     return newComponent;
 116:   }
 117: 
 118:   /**
 119:    * Add the specified component to the layout. 
 120:    * @param key must be one of VIEWPORT, VERTICAL_SCROLLBAR,
 121:    * HORIZONTAL_SCROLLBAR, ROW_HEADER, COLUMN_HEADER,
 122:    * LOWER_RIGHT_CORNER, LOWER_LEFT_CORNER, UPPER_RIGHT_CORNER,
 123:    * UPPER_LEFT_CORNER.
 124:    * @param component the Component to add
 125:    * @throws IllegalArgumentException if key is not as above
 126:    */
 127:   public void addLayoutComponent(String key, Component component) 
 128:   {
 129:     if (key == VIEWPORT)
 130:       viewport = (JViewport) component;
 131:     else if (key == VERTICAL_SCROLLBAR)
 132:       vsb = (JScrollBar) component;
 133:     else if (key == HORIZONTAL_SCROLLBAR)
 134:       hsb = (JScrollBar) component;
 135:     else if (key == ROW_HEADER)
 136:       rowHead = (JViewport) component;
 137:     else if (key == COLUMN_HEADER)
 138:       colHead = (JViewport) component;
 139:     else if (key == LOWER_RIGHT_CORNER)
 140:       lowerRight = component;
 141:     else if (key == UPPER_RIGHT_CORNER)
 142:       upperRight = component;
 143:     else if (key == LOWER_LEFT_CORNER)
 144:       lowerLeft = component;
 145:     else if (key == UPPER_LEFT_CORNER)
 146:       upperLeft = component;
 147:     else
 148:       throw new IllegalArgumentException();
 149:   }
 150: 
 151:   public void removeLayoutComponent(Component component) 
 152:   {
 153:     if (component == viewport)
 154:       viewport = null;
 155:     else if (component == vsb)
 156:       vsb = null;
 157:     else if (component == hsb)
 158:       hsb = null;
 159:     else if (component == rowHead)
 160:       rowHead = null;
 161:     else if (component == colHead)
 162:       colHead = null;
 163:     else if (component == lowerRight)
 164:       lowerRight = null;
 165:     else if (component == upperRight)
 166:       upperRight = null;
 167:     else if (component == lowerLeft)
 168:       lowerLeft = null;
 169:     else if (component == upperLeft)
 170:       upperLeft = null;
 171:   }
 172: 
 173:   public int getVerticalScrollBarPolicy()
 174:   {
 175:     return vsbPolicy;
 176:   }
 177:   
 178:   /**
 179:    * Sets the vertical scrollbar policy.
 180:    * @param policy must be one of VERTICAL_SCROLLBAR_AS_NEEDED,
 181:    * VERTICAL_SCROLLBAR_NEVER, VERTICAL_SCROLLBAR_ALWAYS.
 182:    * @throws IllegalArgumentException if policy is not one of the valid
 183:    * JScrollBar policies.
 184:    */
 185:   public void setVerticalScrollBarPolicy(int policy)
 186:   {
 187:     if (policy != VERTICAL_SCROLLBAR_AS_NEEDED && 
 188:         policy != VERTICAL_SCROLLBAR_NEVER &&
 189:         policy != VERTICAL_SCROLLBAR_ALWAYS)
 190:       throw new IllegalArgumentException("Illegal Scrollbar Policy");
 191:     vsbPolicy = policy;
 192:   }
 193: 
 194:   public int getHorizontalScrollBarPolicy()
 195:   {
 196:     return hsbPolicy;
 197:   }
 198: 
 199:   /**
 200:    * Sets the horizontal scrollbar policy.
 201:    * @param policy must be one of HORIZONTAL_SCROLLBAR_AS_NEEDED,
 202:    * HORIZONTAL_SCROLLBAR_NEVER, HORIZONTAL_SCROLLBAR_ALWAYS.
 203:    * @throws IllegalArgumentException if policy is not one of the valid 
 204:    * JScrollbar policies.
 205:    */
 206:   public void setHorizontalScrollBarPolicy(int policy)
 207:   {
 208:     if (policy != HORIZONTAL_SCROLLBAR_AS_NEEDED && 
 209:         policy != HORIZONTAL_SCROLLBAR_NEVER &&
 210:         policy != HORIZONTAL_SCROLLBAR_ALWAYS)
 211:       throw new IllegalArgumentException("Illegal Scrollbar Policy");
 212:     hsbPolicy = policy;
 213:   }
 214: 
 215:   public JViewport getViewport()
 216:   {
 217:     return viewport;
 218:   }
 219: 
 220:   public JScrollBar getHorizontalScrollBar()
 221:   {
 222:     return hsb;
 223:   }
 224: 
 225:   public JScrollBar getVerticalScrollBar()
 226:   {
 227:     return vsb;
 228:   }
 229: 
 230:   public JViewport getRowHeader()
 231:   {
 232:     return rowHead;
 233:   }
 234: 
 235:   public JViewport getColumnHeader()
 236:   {
 237:     return colHead;
 238:   }
 239: 
 240:   /**
 241:    * Returns the Component at the specified corner.
 242:    * @param key the corner.
 243:    * @return the Component at the specified corner, or null if
 244:    * key is not one of the four valid corners.
 245:    */
 246:   public Component getCorner(String key)
 247:   {
 248:     if (key == LOWER_RIGHT_CORNER)
 249:       return lowerRight;
 250:     else if (key == UPPER_RIGHT_CORNER)
 251:       return upperRight;
 252:     else if (key == LOWER_LEFT_CORNER)
 253:       return lowerLeft;
 254:     else if (key == UPPER_LEFT_CORNER)
 255:       return upperLeft;
 256:     return null;
 257:   }
 258: 
 259:   public Dimension preferredLayoutSize(Container parent) 
 260:   {
 261:     // Sun's implementation simply throws a ClassCastException if
 262:     // parent is no JScrollPane, so do we.
 263:     JScrollPane sc = (JScrollPane) parent;
 264:     Dimension viewportSize = viewport.getPreferredSize();
 265:     Dimension viewSize = viewport.getViewSize();
 266:     int width = viewportSize.width;
 267:     int height = viewportSize.height;
 268: 
 269:     // horizontal scrollbar needed if the view's preferred width
 270:     // is larger than the viewport's preferred width
 271:     if (hsb != null && viewSize.width > viewportSize.width)
 272:       height += hsb.getPreferredSize().height;
 273: 
 274:     // vertical scrollbar needed if the view's preferred height
 275:     // is larger than the viewport's preferred height
 276:     if (vsb != null && viewSize.height > viewportSize.height)
 277:       width += vsb.getPreferredSize().width;
 278:     if (rowHead != null && rowHead.isVisible())
 279:       width += rowHead.getPreferredSize().width;
 280:     if (colHead != null && colHead.isVisible())
 281:       height += colHead.getPreferredSize().height;
 282: 
 283:     // Add insets of viewportBorder if present.
 284:     Border vpBorder = sc.getViewportBorder();
 285:     if (vpBorder != null)
 286:       {
 287:         Insets i = vpBorder.getBorderInsets(sc);
 288:         width += i.left + i.right;
 289:         height += i.top + i.bottom;
 290:       }
 291: 
 292:     Insets i = sc.getInsets();
 293:     return new Dimension(width + i.left + i.right,
 294:                          height + i.left + i.right);
 295:   }
 296: 
 297:   public Dimension minimumLayoutSize(Container parent)
 298:   {
 299:     // Sun's implementation simply throws a ClassCastException if
 300:     // parent is no JScrollPane, so do we.
 301:     JScrollPane sc = (JScrollPane) parent;
 302:     Insets i = sc.getInsets();
 303:     Dimension viewportMinSize = sc.getViewport().getMinimumSize();
 304: 
 305:     int width = i.left + i.right + viewportMinSize.width;
 306:     if (sc.getVerticalScrollBarPolicy()
 307:         != JScrollPane.VERTICAL_SCROLLBAR_NEVER)
 308:       width += sc.getVerticalScrollBar().getMinimumSize().width;
 309: 
 310:     int height = i.top + i.bottom + viewportMinSize.height;
 311:     if (sc.getHorizontalScrollBarPolicy()
 312:         != JScrollPane.HORIZONTAL_SCROLLBAR_NEVER)
 313:       height += sc.getHorizontalScrollBar().getMinimumSize().height;
 314: 
 315:     // Add insets of viewportBorder if present.
 316:     Border vpBorder = sc.getViewportBorder();
 317:     if (vpBorder != null)
 318:       {
 319:         i = vpBorder.getBorderInsets(sc);
 320:         width += i.left + i.right;
 321:         height += i.top + i.bottom;
 322:       }
 323: 
 324:     return new Dimension(width, height);
 325:   }
 326: 
 327:   /**
 328:    *
 329:    *     +----+--------------------+----+ y1
 330:    *     | c1 |   column header    | c2 |
 331:    *     +----+--------------------+----+ y2
 332:    *     | r  |                    | v  |
 333:    *     | o  |                    |    |
 334:    *     | w  |                    | s  |
 335:    *     |    |                    | r  |
 336:    *     | h  |                    | o  |
 337:    *     | e  |      viewport      | l  |
 338:    *     | a  |                    | l  |
 339:    *     | d  |                    | b  |
 340:    *     | e  |                    | a  |
 341:    *     | r  |                    | r  |
 342:    *     +----+--------------------+----+ y3
 343:    *     | c3 |    h scrollbar     | c4 |
 344:    *     +----+--------------------+----+ y4
 345:    *    x1   x2                   x3   x4
 346:    *   
 347:    */
 348:   public void layoutContainer(Container parent)
 349:   {
 350:     // Sun's implementation simply throws a ClassCastException if
 351:     // parent is no JScrollPane, so do we.
 352:     JScrollPane sc = (JScrollPane) parent;
 353:     JViewport viewport = sc.getViewport();
 354:     Component view = viewport.getView();
 355:     
 356:     // If there is no view in the viewport, there is no work to be done.
 357:     if (view == null)
 358:       return;
 359:     
 360:     Dimension viewSize = viewport.getView().getPreferredSize();
 361: 
 362:     int x1 = 0, x2 = 0, x3 = 0, x4 = 0;
 363:     int y1 = 0, y2 = 0, y3 = 0, y4 = 0;
 364:     Rectangle scrollPaneBounds = SwingUtilities.calculateInnerArea(sc, null);
 365: 
 366:     // If there is a viewportBorder, remove its insets from the available
 367:     // space.
 368:     Border vpBorder = sc.getViewportBorder();
 369:     Insets vpi;
 370:     if (vpBorder != null)
 371:       vpi = vpBorder.getBorderInsets(sc);
 372:     else
 373:       vpi = new Insets(0, 0, 0, 0);
 374: 
 375:     x1 = scrollPaneBounds.x;
 376:     y1 = scrollPaneBounds.y;
 377:     x4 = scrollPaneBounds.x + scrollPaneBounds.width;
 378:     y4 = scrollPaneBounds.y + scrollPaneBounds.height;
 379:     if (colHead != null)
 380:       y2 = y1 + colHead.getPreferredSize().height;
 381:     else
 382:       y2 = y1;
 383: 
 384:     if (rowHead != null)
 385:       x2 = x1 + rowHead.getPreferredSize().width;
 386:     else
 387:       x2 = x1;
 388: 
 389:     int vsbPolicy = sc.getVerticalScrollBarPolicy();
 390:     int hsbPolicy = sc.getHorizontalScrollBarPolicy();
 391:     
 392:     int vsWidth = 0;
 393:     int hsHeight = 0;
 394: 
 395:     boolean showVsb = 
 396:       (vsb != null)
 397:       && ((vsbPolicy == VERTICAL_SCROLLBAR_ALWAYS)
 398:           || (vsbPolicy == VERTICAL_SCROLLBAR_AS_NEEDED 
 399:               && viewSize.height > (y4 - y2)));
 400:     
 401:     if (showVsb)
 402:       vsWidth = vsb.getPreferredSize().width;
 403:     
 404:     // The horizontal scroll bar may become necessary if the vertical scroll
 405:     // bar appears, reducing the space, left for the component.
 406:     
 407:     boolean showHsb = 
 408:       (hsb != null)
 409:       && ((hsbPolicy == HORIZONTAL_SCROLLBAR_ALWAYS)
 410:           || (hsbPolicy == HORIZONTAL_SCROLLBAR_AS_NEEDED 
 411:               && viewSize.width > (x4 - x2 - vsWidth)));
 412:     
 413:     if (showHsb)
 414:       hsHeight = hsb.getPreferredSize().height;
 415:     
 416:     // If the horizontal scroll bar appears, and the vertical scroll bar
 417:     // was not necessary assuming that there is no horizontal scroll bar,
 418:     // the vertical scroll bar may become necessary because the horizontal
 419:     // scroll bar reduces the vertical space for the component.
 420:     if (!showVsb)
 421:       {
 422:         showVsb = 
 423:           (vsb != null)
 424:           && ((vsbPolicy == VERTICAL_SCROLLBAR_ALWAYS)
 425:               || (vsbPolicy == VERTICAL_SCROLLBAR_AS_NEEDED 
 426:                   && viewSize.height > (y4 - y2)));
 427:     
 428:         if (showVsb)
 429:           vsWidth = vsb.getPreferredSize().width;
 430:       }
 431: 
 432:     x3 = x4 - vsWidth;
 433:     y3 = y4 - hsHeight;
 434: 
 435:     // now set the layout
 436:     if (viewport != null)
 437:       viewport.setBounds(new Rectangle(x2 + vpi.left, y2 + vpi.top,
 438:                                        x3 - x2 - vpi.left - vpi.right,
 439:                                        y3 - y2 - vpi.top - vpi.bottom));
 440: 
 441:     if (colHead != null)
 442:       colHead.setBounds(new Rectangle(x2, y1, x3 - x2, y2 - y1));
 443: 
 444:     if (rowHead != null)
 445:       rowHead.setBounds(new Rectangle(x1, y2, x2 - x1, y3 - y2));
 446: 
 447:     if (showVsb)
 448:       {
 449:         vsb.setVisible(true);
 450:         vsb.setBounds(new Rectangle(x3, y2, x4 - x3, y3 - y2 ));
 451:       }
 452:     else if (vsb != null)
 453:       vsb.setVisible(false);
 454: 
 455:     if (showHsb)
 456:       {
 457:         hsb.setVisible(true);
 458:         hsb.setBounds(new Rectangle(x2 , y3, x3 - x2, y4 - y3));
 459:       }
 460:     else if (hsb != null)
 461:       hsb.setVisible(false);
 462: 
 463:     if (upperLeft != null)
 464:       upperLeft.setBounds(new Rectangle(x1, y1, x2 - x1, y2 - y1));
 465: 
 466:     if (upperRight != null)
 467:       upperRight.setBounds(new Rectangle(x3, y1, x4 - x3, y2 - y1));
 468: 
 469:     if (lowerLeft != null)
 470:       lowerLeft.setBounds(new Rectangle(x1, y3, x2 - x1, y4 - y3));
 471: 
 472:     if (lowerRight != null)
 473:       lowerRight.setBounds(new Rectangle(x3, y3, x4 - x3, y4 - y3));
 474:   }
 475: 
 476:   /**
 477:    * Returns the bounds of the border around a ScrollPane's viewport.
 478:    *
 479:    * @param scrollPane the ScrollPane for which's viewport the border
 480:    *     is requested
 481:    *
 482:    * @deprecated As of Swing 1.1 replaced by
 483:    *     {@link javax.swing.JScrollPane#getViewportBorderBounds}.
 484:    */
 485:   public Rectangle getViewportBorderBounds(JScrollPane scrollPane) 
 486:   {
 487:     return null;
 488:   }
 489: 
 490: 
 491: }