Frames | No Frames |
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