Source for java.awt.ScrollPane

   1: /* ScrollPane.java -- Scrolling window
   2:    Copyright (C) 1999, 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 java.awt;
  40: 
  41: import java.awt.event.MouseEvent;
  42: import java.awt.peer.ComponentPeer;
  43: import java.awt.peer.ScrollPanePeer;
  44: 
  45: import javax.accessibility.Accessible;
  46: import javax.accessibility.AccessibleContext;
  47: import javax.accessibility.AccessibleRole;
  48: 
  49: 
  50: /**
  51:   * This widget provides a scrollable region that allows a single 
  52:   * subcomponent to be viewed through a smaller window.
  53:   *
  54:   * @author Aaron M. Renn (arenn@urbanophile.com)
  55:   */
  56: public class ScrollPane extends Container implements Accessible
  57: {
  58: 
  59: /*
  60:  * Static Variables
  61:  */
  62: 
  63: /**
  64:   * Constant indicating that scrollbars are created as needed in this
  65:   * windows.
  66:   */
  67: public static final int SCROLLBARS_AS_NEEDED = 0;
  68: 
  69: /**
  70:   * Constant indicating that scrollbars are always displayed in this
  71:   * window.
  72:   */
  73: public static final int SCROLLBARS_ALWAYS = 1;
  74: 
  75: /**
  76:   * Constant indicating that scrollbars are never displayed in this window.
  77:   */
  78: public static final int SCROLLBARS_NEVER = 2;
  79: 
  80: /**
  81:  * The number used to generate the name returned by getName.
  82:  */
  83: private static transient long next_scrollpane_number;
  84: 
  85: // Serialization constant
  86: private static final long serialVersionUID = 7956609840827222915L;
  87: 
  88: /*************************************************************************/
  89: 
  90: /*
  91:  * Instance Variables
  92:  */
  93: 
  94: /**
  95:   * @serial The horizontal scrollbar for this window.  The methods
  96:   * <code>setMinimum()</code>, <code>setMaximum</code>, and
  97:   * <code>setVisibleAmount</code> must not be called on this scrollbar.
  98:   */
  99: private ScrollPaneAdjustable hAdjustable;
 100: 
 101: /**
 102:   * @serial The vertical scrollbar for this window.  The methods
 103:   * <code>setMinimum()</code>, <code>setMaximum</code>, and
 104:   * <code>setVisibleAmount</code> must not be called on this scrollbar.
 105:   */
 106: private ScrollPaneAdjustable vAdjustable;
 107: 
 108: /**
 109:   * @serial Indicates when scrollbars are displayed in this window, will
 110:   * be one of the constants from this class.
 111:   */
 112: private int scrollbarDisplayPolicy;
 113: 
 114: // Current scroll position
 115: private Point scrollPosition = new Point(0, 0);
 116: 
 117: private boolean wheelScrollingEnabled;
 118: 
 119: /*************************************************************************/
 120: 
 121: /*
 122:  * Constructors
 123:  */
 124: 
 125: /**
 126:   * Initializes a new instance of <code>ScrollPane</code> with a default
 127:   * scrollbar policy of <code>SCROLLBARS_AS_NEEDED</code>.
 128:   *
 129:   * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true.
 130:   */
 131: public
 132: ScrollPane()
 133: {
 134:   this(SCROLLBARS_AS_NEEDED);
 135: }
 136: 
 137: /*************************************************************************/
 138: 
 139: /**
 140:   * Initializes a new instance of <code>ScrollPane</code> with the
 141:   * specified scrollbar policy.
 142:   *
 143:   * @param scrollbarDisplayPolicy When to display scrollbars, which must
 144:   * be one of the constants defined in this class.
 145:   *
 146:   * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true.
 147:   */
 148: public
 149: ScrollPane(int scrollbarDisplayPolicy)
 150: {
 151:   if (GraphicsEnvironment.isHeadless ())
 152:     throw new HeadlessException ();
 153: 
 154:   this.scrollbarDisplayPolicy = scrollbarDisplayPolicy;
 155: 
 156:   if (scrollbarDisplayPolicy != SCROLLBARS_ALWAYS
 157:       && scrollbarDisplayPolicy != SCROLLBARS_AS_NEEDED
 158:       && scrollbarDisplayPolicy != SCROLLBARS_NEVER)
 159:     throw new IllegalArgumentException("Bad scrollbarDisplayPolicy: " +
 160:                                        scrollbarDisplayPolicy);
 161: 
 162:   if (scrollbarDisplayPolicy != SCROLLBARS_NEVER)
 163:     {
 164:       hAdjustable = new ScrollPaneAdjustable (this, Scrollbar.HORIZONTAL);
 165:       vAdjustable = new ScrollPaneAdjustable (this, Scrollbar.VERTICAL);
 166:     }
 167: 
 168:   wheelScrollingEnabled = true;
 169: 
 170:   // Default size.
 171:   setSize(100,100);
 172: }
 173: 
 174: /*************************************************************************/
 175: 
 176: /*
 177:  * Instance Variables
 178:  */
 179: 
 180: /**
 181:   * Returns the current scrollbar display policy.
 182:   *
 183:   * @return The current scrollbar display policy.
 184:   */
 185: public int
 186: getScrollbarDisplayPolicy()
 187: {
 188:   return(scrollbarDisplayPolicy);
 189: }
 190: 
 191: /*************************************************************************/
 192: 
 193: /**
 194:   * Returns the horizontal scrollbar for this object.  If the scrollbar
 195:   * display policy is set to <code>SCROLLBARS_NEVER</code> then this
 196:   * will be <code>null</code>.
 197:   *
 198:   * @return The horizontal scrollbar for this window.
 199:   */
 200: public Adjustable
 201: getHAdjustable()
 202: {
 203:   return(hAdjustable);
 204: }
 205: 
 206: /*************************************************************************/
 207: 
 208: /**
 209:   * Returns the vertical scrollbar for this object.  If the scrollbar
 210:   * display policy is set to <code>SCROLLBARS_NEVER</code> then this
 211:   * will be <code>null</code>.
 212:   *
 213:   * @return The horizontal scrollbar for this window.
 214:   */
 215: public Adjustable
 216: getVAdjustable()
 217: {
 218:   return(vAdjustable);
 219: }
 220: 
 221: /*************************************************************************/
 222: 
 223: /**
 224:   * Returns the current viewport size.  The viewport is the region of
 225:   * this object's window where the child is actually displayed.
 226:   *
 227:   * @return The viewport size.
 228:   */
 229: public Dimension getViewportSize ()
 230: { 
 231:   Dimension viewsize = getSize ();
 232:   Insets insets = getInsets ();
 233: 
 234:   viewsize.width -= (insets.left + insets.right);
 235:   viewsize.height -= (insets.top + insets.bottom);
 236: 
 237:   Component[] list = getComponents();
 238:   if ((list == null) || (list.length <= 0))
 239:     return viewsize;
 240:   
 241:   Dimension dim = list[0].getPreferredSize();
 242:   
 243:   if (dim.width <= 0 && dim.height <= 0)
 244:     return viewsize;
 245: 
 246:   int vScrollbarWidth = getVScrollbarWidth ();
 247:   int hScrollbarHeight = getHScrollbarHeight ();
 248: 
 249:   if (scrollbarDisplayPolicy == SCROLLBARS_ALWAYS)
 250:     {
 251:       viewsize.width -= vScrollbarWidth;
 252:       viewsize.height -= hScrollbarHeight;
 253:       return viewsize;
 254:     }
 255: 
 256:   if (scrollbarDisplayPolicy == SCROLLBARS_NEVER)
 257:     return viewsize;
 258: 
 259:   // The scroll policy is SCROLLBARS_AS_NEEDED, so we need to see if
 260:   // either scrollbar is needed.
 261: 
 262:   // Assume we don't need either scrollbar.
 263:   boolean mayNeedVertical = false;
 264:   boolean mayNeedHorizontal = false;
 265: 
 266:   boolean needVertical = false;
 267:   boolean needHorizontal = false;
 268: 
 269:   // Check if we need vertical scrollbars.  If we do, then we need to
 270:   // subtract the width of the vertical scrollbar from the viewport's
 271:   // width.
 272:   if (dim.height > viewsize.height)
 273:     needVertical = true;
 274:   else if (dim.height > (viewsize.height - hScrollbarHeight))
 275:     // This is tricky.  In this case the child is tall enough that its
 276:     // bottom edge would be covered by a horizontal scrollbar, if one
 277:     // were present.  This means that if there's a horizontal
 278:     // scrollbar then we need a vertical scrollbar.
 279:     mayNeedVertical = true;
 280: 
 281:   if (dim.width > viewsize.width)
 282:     needHorizontal = true;
 283:   else if (dim.width > (viewsize.width - vScrollbarWidth))
 284:     mayNeedHorizontal = true;
 285:   
 286:   if (needVertical && mayNeedHorizontal)
 287:     needHorizontal = true;
 288: 
 289:   if (needHorizontal && mayNeedVertical)
 290:     needVertical = true;
 291: 
 292:   if (needHorizontal)
 293:     viewsize.height -= hScrollbarHeight;
 294: 
 295:   if (needVertical)
 296:     viewsize.width -= vScrollbarWidth;
 297:   
 298:   return viewsize;
 299: }
 300: 
 301: /*************************************************************************/
 302: 
 303: /**
 304:   * Returns the height of a horizontal scrollbar.
 305:   *
 306:   * @return The height of a horizontal scrollbar.
 307:   */
 308: public int
 309: getHScrollbarHeight()
 310: {
 311:   ScrollPanePeer spp = (ScrollPanePeer)getPeer();
 312:   if (spp != null)
 313:     return(spp.getHScrollbarHeight());
 314:   else
 315:     return(0); // FIXME: What to do here?
 316: }
 317: 
 318: /*************************************************************************/
 319: 
 320: /**
 321:   * Returns the width of a vertical scrollbar.
 322:   *
 323:   * @return The width of a vertical scrollbar.
 324:   */
 325: public int
 326: getVScrollbarWidth()
 327: {
 328:   ScrollPanePeer spp = (ScrollPanePeer)getPeer();
 329:   if (spp != null)
 330:     return(spp.getVScrollbarWidth());
 331:   else
 332:     return(0); // FIXME: What to do here?
 333: }
 334: 
 335: /*************************************************************************/
 336: 
 337: /**
 338:   * Returns the current scroll position of the viewport.
 339:   *
 340:   * @return The current scroll position of the viewport.
 341:   * 
 342:   * @throws NullPointerException if the scrollpane does have a child.
 343:   */
 344: public Point
 345: getScrollPosition()
 346: {
 347:   if (getComponentCount() == 0)
 348:     throw new NullPointerException();
 349:   
 350:   int x = 0;
 351:   int y = 0;
 352: 
 353:   Adjustable v = getVAdjustable();
 354:   Adjustable h = getHAdjustable();
 355: 
 356:   if (v != null)
 357:     y = v.getValue();
 358:   if (h != null)
 359:     x = h.getValue();
 360: 
 361:   return(new Point(x, y));
 362: }
 363: 
 364: /*************************************************************************/
 365: 
 366: /**
 367:   * Sets the scroll position to the specified value.
 368:   *
 369:   * @param scrollPosition The new scrollPosition.
 370:   *
 371:   * @exception IllegalArgumentException If the specified value is outside
 372:   * the legal scrolling range.
 373:   */
 374: public void
 375: setScrollPosition(Point scrollPosition) throws IllegalArgumentException
 376: {
 377:   setScrollPosition(scrollPosition.x, scrollPosition.y);
 378: }
 379: 
 380: /*************************************************************************/
 381: 
 382: /**
 383:   * Sets the scroll position to the specified value.
 384:   *
 385:   * @param x The new X coordinate of the scroll position.
 386:   * @param y The new Y coordinate of the scroll position.
 387:   *
 388:   * @throws NullPointerException if scrollpane does not have a child.
 389:   * 
 390:   * @exception IllegalArgumentException If the specified value is outside
 391:   * the legal scrolling range.
 392:   */
 393: public void
 394: setScrollPosition(int x, int y)
 395: {
 396:   if (getComponentCount() == 0)
 397:     throw new NullPointerException("child is null");
 398: 
 399:   if (x > (int) (getComponent(0).getWidth() - getViewportSize().getWidth()))
 400:     x = (int) (getComponent(0).getWidth() - getViewportSize().getWidth());
 401:   if (y > (int) (getComponent(0).getHeight() - getViewportSize().getHeight()))
 402:     y = (int) (getComponent(0).getHeight() - getViewportSize().getHeight());
 403: 
 404:   if (x < 0)
 405:     x = 0;
 406:   if (y < 0)
 407:     y = 0;
 408:     
 409:   Adjustable h = getHAdjustable();
 410:   Adjustable v = getVAdjustable();
 411:   
 412:   if (h != null)
 413:     h.setValue(x);
 414:   if (v != null)
 415:     v.setValue(y);
 416:    
 417:   ScrollPanePeer spp = (ScrollPanePeer)getPeer();
 418:   if (spp != null)
 419:     spp.setScrollPosition(x, y);
 420: }
 421: 
 422: /*************************************************************************/
 423: 
 424: /**
 425:   * Notifies this object that it should create its native peer.
 426:   */
 427: public void
 428: addNotify()
 429: {
 430:   if (peer != null)
 431:     return;
 432: 
 433:   setPeer((ComponentPeer)getToolkit().createScrollPane(this));
 434:   super.addNotify();
 435: 
 436:   Component[] list = getComponents();
 437:   if (list != null && list.length > 0 && list[0].isLightweight())
 438:   {
 439:     Panel panel = new Panel();
 440:     panel.setLayout(new BorderLayout());
 441:     panel.add(list[0], BorderLayout.CENTER);
 442:     add(panel);
 443:   }
 444: }
 445: 
 446: /*************************************************************************/
 447: 
 448: /**
 449:   * Notifies this object that it should destroy its native peers.
 450:   */
 451: public void
 452: removeNotify()
 453: {
 454:   super.removeNotify();
 455: }
 456: 
 457: /*************************************************************************/
 458: 
 459: /**
 460:   * Adds the specified child component to this container.  A 
 461:   * <code>ScrollPane</code> can have at most one child, so if a second
 462:   * one is added, then first one is removed.
 463:   *
 464:   * @param component The component to add to this container.
 465:   * @param constraints A list of layout constraints for this object.
 466:   * @param index The index at which to add the child, which is ignored
 467:   * in this implementation.
 468:   */
 469:   protected final void addImpl (Component component, Object constraints,
 470:                 int index)
 471: {
 472:   Component[] list = getComponents();
 473:   if ((list != null) && (list.length > 0))
 474:     remove(list[0]);
 475: 
 476:   super.addImpl(component, constraints, index);
 477: }
 478: 
 479: /*************************************************************************/
 480: 
 481: /**
 482:   * Lays out this component.  This consists of resizing the sole child
 483:   * component to its perferred size.
 484:   */
 485: public void
 486: doLayout()
 487: {
 488:   layout ();
 489: }
 490: 
 491: /*************************************************************************/
 492: 
 493: /**
 494:   * Lays out this component.  This consists of resizing the sole child
 495:   * component to its perferred size.
 496:   *
 497:   * @deprecated This method is deprecated in favor of
 498:   * <code>doLayout()</code>.
 499:   */
 500: public void
 501: layout()
 502: {
 503:   Component[] list = getComponents ();
 504:   if ((list != null) && (list.length > 0))
 505:     {
 506:       Dimension dim = list[0].getPreferredSize ();
 507:       Dimension vp = getViewportSize ();
 508: 
 509:       if (dim.width < vp.width)
 510:     dim.width = vp.width;
 511: 
 512:       if (dim.height < vp.height)
 513:     dim.height = vp.height;
 514: 
 515:       ScrollPanePeer peer = (ScrollPanePeer) getPeer ();
 516:       if (peer != null)
 517:     peer.childResized (dim.width, dim.height);
 518: 
 519:       list[0].setSize (dim);
 520: 
 521:       Point p = getScrollPosition ();
 522:       if (p.x > dim.width)
 523:         p.x = dim.width;
 524:       if (p.y > dim.height)
 525:         p.y = dim.height;
 526: 
 527:       setScrollPosition (p);
 528:       
 529:       list[0].setLocation(new Point());
 530:     }
 531: }
 532: 
 533: /*************************************************************************/
 534: 
 535: /**
 536:   * This method overrides its superclass method to ensure no layout
 537:   * manager is set for this container.  <code>ScrollPane</code>'s do
 538:   * not have layout managers.
 539:   *
 540:   * @param layoutManager Ignored
 541:   * @throws AWTError Always throws this error when called. 
 542:   */
 543: public final void
 544: setLayout(LayoutManager layoutManager)
 545: {
 546:   throw new AWTError("ScrollPane controls layout");
 547: }
 548: 
 549: /*************************************************************************/
 550: 
 551: /**
 552:   * Prints all of the components in this container.
 553:   *
 554:   * @param graphics The desired graphics context for printing.
 555:   */
 556: public void
 557: printComponents(Graphics graphics)
 558: {
 559:   super.printComponents(graphics);
 560: }
 561: 
 562: /*************************************************************************/
 563: 
 564: /**
 565:   * Returns a debug string for this object.
 566:   *
 567:   * @return A debug string for this object.
 568:   */
 569: public String
 570: paramString()
 571: {
 572:   Insets insets = getInsets();
 573:   return getName() + ","
 574:          + getX() + ","
 575:          + getY() + ","
 576:          + getWidth() + "x" + getHeight() + ","
 577:          + getIsValidString() + ","
 578:          + "ScrollPosition=(" + scrollPosition.x + "," 
 579:                               + scrollPosition.y + "),"
 580:          + "Insets=(" + insets.top + ","
 581:                       + insets.left + ","
 582:                       + insets.bottom + ","
 583:                       + insets.right + "),"
 584:          + "ScrollbarDisplayPolicy=" + getScrollbarDisplayPolicyString() + ","
 585:          + "wheelScrollingEnabled=" + isWheelScrollingEnabled();
 586: }
 587: 
 588: private String
 589: getScrollbarDisplayPolicyString()
 590: {
 591:   if (getScrollbarDisplayPolicy() == 0)
 592:     return "as-needed";
 593:   else if (getScrollbarDisplayPolicy() == 1)
 594:     return "always";
 595:   else
 596:     return "never";
 597: }
 598: 
 599: private String 
 600: getIsValidString()
 601: {
 602:   if (isValid())
 603:     return "valid";
 604:   else
 605:     return "invalid";
 606: }
 607: 
 608:   /**
 609:    * Tells whether or not an event is enabled.
 610:    *
 611:    * @since 1.4
 612:    */
 613:   protected boolean eventTypeEnabled (int type)
 614:   {
 615:     if (type == MouseEvent.MOUSE_WHEEL)
 616:       return wheelScrollingEnabled;
 617: 
 618:     return super.eventTypeEnabled (type);
 619:   }
 620: 
 621:   /**
 622:    * Tells whether or not wheel scrolling is enabled.
 623:    *
 624:    * @since 1.4
 625:    */
 626:   public boolean isWheelScrollingEnabled ()
 627:   {
 628:     return wheelScrollingEnabled;
 629:   }
 630: 
 631:   /**
 632:    * Enables/disables wheel scrolling.
 633:    *
 634:    * @since 1.4
 635:    */
 636:   public void setWheelScrollingEnabled (boolean enable)
 637:   {
 638:     wheelScrollingEnabled = enable;
 639:   }
 640:   
 641:   protected class AccessibleAWTScrollPane extends AccessibleAWTContainer
 642:   {
 643:     private static final long serialVersionUID = 6100703663886637L;
 644: 
 645:     public AccessibleRole getAccessibleRole()
 646:     {
 647:       return AccessibleRole.SCROLL_PANE;
 648:     }
 649:   }
 650: 
 651:   /**
 652:    * Gets the AccessibleContext associated with this <code>ScrollPane</code>.
 653:    * The context is created, if necessary.
 654:    *
 655:    * @return the associated context
 656:    */
 657:   public AccessibleContext getAccessibleContext()
 658:   {
 659:     /* Create the context if this is the first request */
 660:     if (accessibleContext == null)
 661:       accessibleContext = new AccessibleAWTScrollPane();
 662:     return accessibleContext;
 663:   }
 664:   
 665:   /**
 666:    * Generate a unique name for this <code>ScrollPane</code>.
 667:    *
 668:    * @return A unique name for this <code>ScrollPane</code>.
 669:    */
 670:   String generateName()
 671:   {
 672:     return "scrollpane" + getUniqueLong();
 673:   }
 674: 
 675:   private static synchronized long getUniqueLong()
 676:   {
 677:     return next_scrollpane_number++;
 678:   }
 679:   
 680: } // class ScrollPane