Frames | No Frames |
1: /* Scrollbar.java -- AWT Scrollbar widget 2: Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 3: Free Software Foundation, Inc. 4: 5: This file is part of GNU Classpath. 6: 7: GNU Classpath is free software; you can redistribute it and/or modify 8: it under the terms of the GNU General Public License as published by 9: the Free Software Foundation; either version 2, or (at your option) 10: any later version. 11: 12: GNU Classpath is distributed in the hope that it will be useful, but 13: WITHOUT ANY WARRANTY; without even the implied warranty of 14: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15: General Public License for more details. 16: 17: You should have received a copy of the GNU General Public License 18: along with GNU Classpath; see the file COPYING. If not, write to the 19: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 20: 02110-1301 USA. 21: 22: Linking this library statically or dynamically with other modules is 23: making a combined work based on this library. Thus, the terms and 24: conditions of the GNU General Public License cover the whole 25: combination. 26: 27: As a special exception, the copyright holders of this library give you 28: permission to link this library with independent modules to produce an 29: executable, regardless of the license terms of these independent 30: modules, and to copy and distribute the resulting executable under 31: terms of your choice, provided that you also meet, for each linked 32: independent module, the terms and conditions of the license of that 33: module. An independent module is a module which is not derived from 34: or based on this library. If you modify this library, you may extend 35: this exception to your version of the library, but you are not 36: obligated to do so. If you do not wish to do so, delete this 37: exception statement from your version. */ 38: 39: 40: package java.awt; 41: 42: import java.awt.event.AdjustmentEvent; 43: import java.awt.event.AdjustmentListener; 44: import java.awt.peer.ScrollbarPeer; 45: import java.util.EventListener; 46: 47: import javax.accessibility.Accessible; 48: import javax.accessibility.AccessibleContext; 49: import javax.accessibility.AccessibleRole; 50: import javax.accessibility.AccessibleState; 51: import javax.accessibility.AccessibleStateSet; 52: import javax.accessibility.AccessibleValue; 53: 54: /** 55: * This class implements a scrollbar widget. 56: * 57: * @author Aaron M. Renn (arenn@urbanophile.com) 58: * @author Tom Tromey (tromey@cygnus.com) 59: * @author Andrew John Hughes (gnu_andrew@member.fsf.org) 60: */ 61: public class Scrollbar extends Component implements Accessible, Adjustable 62: { 63: // FIXME: Serialization readObject/writeObject 64: 65: /** 66: * Constant indicating that a scrollbar is horizontal. 67: */ 68: public static final int HORIZONTAL = 0; 69: 70: /** 71: * Constant indicating that a scrollbar is vertical. 72: */ 73: public static final int VERTICAL = 1; 74: 75: /** 76: * Serialization Constant. 77: */ 78: private static final long serialVersionUID = 8451667562882310543L; 79: 80: /** 81: * @serial The amount by which the value of the scrollbar is changed 82: * when incrementing in line mode. 83: */ 84: private int lineIncrement; 85: 86: /** 87: * @serial The amount by which the value of the scrollbar is changed 88: * when incrementing in page mode. 89: */ 90: private int pageIncrement; 91: 92: /** 93: * @serial The maximum value for this scrollbar 94: */ 95: private int maximum; 96: 97: /** 98: * @serial The minimum value for this scrollbar 99: */ 100: private int minimum; 101: 102: /** 103: * @serial The orientation of this scrollbar, which will be either 104: * the <code>HORIZONTAL</code> or <code>VERTICAL</code> constant 105: * from this class. 106: */ 107: private int orientation; 108: 109: /** 110: * @serial The current value of this scrollbar. 111: */ 112: private int value; 113: 114: /** 115: * @serial The width of the scrollbar's thumb, which is relative 116: * to the minimum and maximum value of the scrollbar. 117: */ 118: private int visibleAmount; 119: 120: /** 121: * List of AdjustmentListener's. 122: */ 123: private AdjustmentListener adjustment_listeners; 124: 125: /** 126: * true if the scrollbar is adjusting, false otherwise. 127: */ 128: private transient boolean valueIsAdjusting = false; 129: 130: /** 131: * The number used to generate the name returned by getName. 132: */ 133: private static transient long next_scrollbar_number; 134: 135: /** 136: * Initializes a new instance of <code>Scrollbar</code> with a 137: * vertical orientation and default values for all other parameters. 138: * 139: * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true, 140: */ 141: public Scrollbar() 142: { 143: this(VERTICAL); 144: } 145: 146: /** 147: * Initializes a new instance of <code>Scrollbar</code> with the 148: * specified orientation and default values for all other parameters. 149: * The orientation must be either the constant <code>HORIZONTAL</code> or 150: * <code>VERTICAL</code> from this class. An incorrect value will throw 151: * an exception. 152: * 153: * @param orientation The orientation of this scrollbar. 154: * 155: * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true, 156: * @exception IllegalArgumentException If the orientation value is not valid. 157: */ 158: public Scrollbar(int orientation) throws IllegalArgumentException 159: { 160: this(orientation, 0, 10, 0, 100); 161: } 162: 163: /** 164: * Initializes a new instance of <code>Scrollbar</code> with the 165: * specified parameters. The orientation must be either the constant 166: * <code>HORIZONTAL</code> or <code>VERTICAL</code>. An incorrect value 167: * will throw an exception. Inconsistent values for other parameters 168: * are silently corrected to valid values. 169: * 170: * @param orientation The orientation of this scrollbar. 171: * @param value The initial value of the scrollbar. 172: * @param visibleAmount The width of the scrollbar thumb. 173: * @param minimum The minimum value of the scrollbar. 174: * @param maximum The maximum value of the scrollbar. 175: * 176: * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true, 177: * @exception IllegalArgumentException If the orientation value is not valid. 178: */ 179: public Scrollbar(int orientation, int value, int visibleAmount, int minimum, 180: int maximum) throws IllegalArgumentException 181: { 182: if (GraphicsEnvironment.isHeadless()) 183: throw new HeadlessException(); 184: 185: if ((orientation != HORIZONTAL) && (orientation != VERTICAL)) 186: throw new IllegalArgumentException("Bad orientation value: " 187: + orientation); 188: 189: this.orientation = orientation; 190: 191: setValues(value, visibleAmount, minimum, maximum); 192: 193: // Default is 1 according to online docs. 194: lineIncrement = 1; 195: 196: // Default is 10 according to javadocs. 197: pageIncrement = 10; 198: } 199: 200: /** 201: * Returns the orientation constant for this object. 202: * 203: * @return The orientation constant for this object. 204: */ 205: public int getOrientation() 206: { 207: return orientation; 208: } 209: 210: /** 211: * Sets the orientation of this scrollbar to the specified value. This 212: * value must be either the constant <code>HORIZONTAL</code> or 213: * <code>VERTICAL</code> from this class or an exception will be thrown. 214: * 215: * @param orientation The new orientation value. 216: * 217: * @exception IllegalArgumentException If the orientation value is not valid. 218: */ 219: public void setOrientation(int orientation) 220: { 221: if ((orientation != HORIZONTAL) && (orientation != VERTICAL)) 222: throw new IllegalArgumentException("Bad orientation value: " 223: + orientation); 224: 225: // FIXME: Communicate to peer? Or must this be called before peer creation? 226: this.orientation = orientation; 227: } 228: 229: /** 230: * Returns the current value for this scrollbar. 231: * 232: * @return The current value for this scrollbar. 233: */ 234: public int getValue() 235: { 236: return value; 237: } 238: 239: /** 240: * Sets the current value for this scrollbar to the specified value. 241: * If this is inconsistent with the minimum and maximum values for this 242: * scrollbar, the value is silently adjusted. 243: * 244: * @param value The new value for this scrollbar. 245: */ 246: public void setValue(int value) 247: { 248: setValues(value, visibleAmount, minimum, maximum); 249: } 250: 251: /** 252: * Returns the maximum value for this scrollbar. 253: * 254: * @return The maximum value for this scrollbar. 255: */ 256: public int getMaximum() 257: { 258: return maximum; 259: } 260: 261: /** 262: * Sets the maximum value for this scrollbar to the specified value. 263: * If the value is less than the current minimum value, it is silent 264: * set to equal the minimum value. 265: * 266: * @param maximum The new maximum value for this scrollbar. 267: */ 268: public void setMaximum(int maximum) 269: { 270: setValues(value, visibleAmount, minimum, maximum); 271: } 272: 273: /** 274: * Returns the minimum value for this scrollbar. 275: * 276: * @return The minimum value for this scrollbar. 277: */ 278: public int getMinimum() 279: { 280: return minimum; 281: } 282: 283: /** 284: * Sets the minimum value for this scrollbar to the specified value. If 285: * this is not consistent with the current value and maximum, it is 286: * silently adjusted to be consistent. 287: * 288: * @param minimum The new minimum value for this scrollbar. 289: */ 290: public void setMinimum(int minimum) 291: { 292: setValues(value, visibleAmount, minimum, maximum); 293: } 294: 295: /** 296: * Returns the width of the scrollbar's thumb, in units relative to the 297: * maximum and minimum value of the scrollbar. 298: * 299: * @return The width of the scrollbar's thumb. 300: */ 301: public int getVisibleAmount() 302: { 303: return getVisible(); 304: } 305: 306: /** 307: * Returns the width of the scrollbar's thumb, in units relative to the 308: * maximum and minimum value of the scrollbar. 309: * 310: * @return The width of the scrollbar's thumb. 311: * 312: * @deprecated This method is deprecated in favor of 313: * <code>getVisibleAmount()</code>. 314: */ 315: public int getVisible() 316: { 317: return visibleAmount; 318: } 319: 320: /** 321: * Sets the width of the scrollbar's thumb, in units relative to the 322: * maximum and minimum value of the scrollbar. 323: * 324: * @param visibleAmount The new visible amount value of the scrollbar. 325: */ 326: public void setVisibleAmount(int visibleAmount) 327: { 328: setValues(value, visibleAmount, minimum, maximum); 329: } 330: 331: /** 332: * Sets the current value, visible amount, minimum, and maximum for this 333: * scrollbar. These values are adjusted to be internally consistent 334: * if necessary. 335: * 336: * @param value The new value for this scrollbar. 337: * @param visibleAmount The new visible amount for this scrollbar. 338: * @param minimum The new minimum value for this scrollbar. 339: * @param maximum The new maximum value for this scrollbar. 340: */ 341: public synchronized void setValues(int value, int visibleAmount, 342: int minimum, int maximum) 343: { 344: if (visibleAmount <= 0) 345: visibleAmount = 1; 346: 347: if (maximum <= minimum) 348: maximum = minimum + 1; 349: 350: if (value < minimum) 351: value = minimum; 352: 353: if (visibleAmount > maximum - minimum) 354: visibleAmount = maximum - minimum; 355: 356: // According to documentation, the actual maximum 357: // value is (maximum - visibleAmount) 358: if (value > maximum - visibleAmount) 359: value = maximum - visibleAmount; 360: 361: ScrollbarPeer peer = (ScrollbarPeer) getPeer(); 362: if (peer != null 363: && (this.value != value || this.visibleAmount != visibleAmount 364: || this.minimum != minimum || this.maximum != maximum)) 365: peer.setValues(value, visibleAmount, minimum, maximum); 366: 367: this.value = value; 368: this.visibleAmount = visibleAmount; 369: this.minimum = minimum; 370: this.maximum = maximum; 371: } 372: 373: /** 374: * Returns the value added or subtracted when the user activates the scrollbar 375: * scroll by a "unit" amount. 376: * 377: * @return The unit increment value. 378: */ 379: public int getUnitIncrement() 380: { 381: return getLineIncrement(); 382: } 383: 384: /** 385: * Returns the value added or subtracted when the user selects the scrollbar 386: * scroll by a "unit" amount control. 387: * 388: * @return The unit increment value. 389: * 390: * @deprecated This method is deprecated in favor of 391: * <code>getUnitIncrement()</code>. 392: */ 393: public int getLineIncrement() 394: { 395: return lineIncrement; 396: } 397: 398: /** 399: * Sets the value added or subtracted to the scrollbar value when the 400: * user selects the scroll by a "unit" amount control. 401: * 402: * @param unitIncrement The new unit increment amount. 403: */ 404: public synchronized void setUnitIncrement(int unitIncrement) 405: { 406: setLineIncrement(unitIncrement); 407: } 408: 409: /** 410: * Sets the value added or subtracted to the scrollbar value when the 411: * user selects the scroll by a "unit" amount control. 412: * 413: * @param lineIncrement The new unit increment amount. 414: * 415: * @deprecated This method is deprecated in favor of 416: * <code>setUnitIncrement()</code>. 417: */ 418: public void setLineIncrement(int lineIncrement) 419: { 420: if (lineIncrement < 0) 421: throw new IllegalArgumentException("Unit increment less than zero."); 422: 423: if (lineIncrement == 0) 424: lineIncrement = 1; 425: 426: if (lineIncrement == this.lineIncrement) 427: return; 428: 429: this.lineIncrement = lineIncrement; 430: 431: ScrollbarPeer peer = (ScrollbarPeer) getPeer(); 432: if (peer != null) 433: peer.setLineIncrement(this.lineIncrement); 434: } 435: 436: /** 437: * Returns the value added or subtracted when the user activates the scrollbar 438: * scroll by a "block" amount. 439: * 440: * @return The block increment value. 441: */ 442: public int getBlockIncrement() 443: { 444: return getPageIncrement(); 445: } 446: 447: /** 448: * Returns the value added or subtracted when the user selects the scrollbar 449: * scroll by a "block" amount control. 450: * 451: * @return The block increment value. 452: * 453: * @deprecated This method is deprecated in favor of 454: * <code>getBlockIncrement()</code>. 455: */ 456: public int getPageIncrement() 457: { 458: return pageIncrement; 459: } 460: 461: /** 462: * Sets the value added or subtracted to the scrollbar value when the 463: * user selects the scroll by a "block" amount control. 464: * 465: * @param blockIncrement The new block increment amount. 466: */ 467: public synchronized void setBlockIncrement(int blockIncrement) 468: { 469: setPageIncrement(blockIncrement); 470: } 471: 472: /** 473: * Sets the value added or subtracted to the scrollbar value when the 474: * user selects the scroll by a "block" amount control. 475: * 476: * @param pageIncrement The new block increment amount. 477: * 478: * @deprecated This method is deprecated in favor of 479: * <code>setBlockIncrement()</code>. 480: */ 481: public void setPageIncrement(int pageIncrement) 482: { 483: if (pageIncrement < 0) 484: throw new IllegalArgumentException("Block increment less than zero."); 485: 486: if (pageIncrement == 0) 487: pageIncrement = 1; 488: 489: if (pageIncrement == this.pageIncrement) 490: return; 491: 492: this.pageIncrement = pageIncrement; 493: 494: ScrollbarPeer peer = (ScrollbarPeer) getPeer(); 495: if (peer != null) 496: peer.setPageIncrement(this.pageIncrement); 497: } 498: 499: /** 500: * Notifies this object to create its native peer. 501: */ 502: public synchronized void addNotify() 503: { 504: if (peer == null) 505: peer = getToolkit().createScrollbar(this); 506: super.addNotify(); 507: } 508: 509: /** 510: * Adds a new adjustment listener to the list of registered listeners 511: * for this object. 512: * 513: * @param listener The listener to add. 514: */ 515: public synchronized void addAdjustmentListener(AdjustmentListener listener) 516: { 517: adjustment_listeners = AWTEventMulticaster.add(adjustment_listeners, 518: listener); 519: enableEvents(AWTEvent.ADJUSTMENT_EVENT_MASK); 520: } 521: 522: /** 523: * Removes the specified listener from the list of registered listeners 524: * for this object. 525: * 526: * @param listener The listener to remove. 527: */ 528: public synchronized void removeAdjustmentListener(AdjustmentListener listener) 529: { 530: adjustment_listeners = AWTEventMulticaster.remove(adjustment_listeners, 531: listener); 532: } 533: 534: /** 535: * Processes events for this scrollbar. It does this by calling 536: * <code>processAdjustmentEvent()</code> if the event is an instance of 537: * <code>AdjustmentEvent</code>, otherwise it calls the superclass to 538: * process the event. 539: * 540: * @param event The event to process. 541: */ 542: protected void processEvent(AWTEvent event) 543: { 544: if (event instanceof AdjustmentEvent) 545: processAdjustmentEvent((AdjustmentEvent) event); 546: else 547: super.processEvent(event); 548: } 549: 550: /** 551: * Processes adjustment events for this object by dispatching them to 552: * any registered listeners. Note that this method will only be called 553: * if adjustment events are enabled. This will happen automatically if 554: * any listeners are registered. Otherwise, it can be enabled by a 555: * call to <code>enableEvents()</code>. 556: * 557: * @param event The event to process. 558: */ 559: protected void processAdjustmentEvent(AdjustmentEvent event) 560: { 561: value = event.getValue(); 562: if (adjustment_listeners != null) 563: adjustment_listeners.adjustmentValueChanged(event); 564: } 565: 566: /** 567: * Package private method to determine whether to call 568: * processEvent() or not. Will handle events from peer and update 569: * the current value. 570: */ 571: void dispatchEventImpl(AWTEvent e) 572: { 573: if (e.id <= AdjustmentEvent.ADJUSTMENT_LAST 574: && e.id >= AdjustmentEvent.ADJUSTMENT_FIRST) 575: { 576: AdjustmentEvent ae = (AdjustmentEvent) e; 577: boolean adjusting = ae.getValueIsAdjusting(); 578: if (adjusting) 579: setValueIsAdjusting(true); 580: try 581: { 582: setValue(((AdjustmentEvent) e).getValue()); 583: if (adjustment_listeners != null 584: || (eventMask & AWTEvent.ADJUSTMENT_EVENT_MASK) != 0) 585: processEvent(e); 586: } 587: finally 588: { 589: if (adjusting) 590: setValueIsAdjusting(false); 591: } 592: } 593: else 594: super.dispatchEventImpl(e); 595: } 596: 597: /** 598: * Returns a debugging string for this object. 599: * 600: * @return A debugging string for this object. 601: */ 602: protected String paramString() 603: { 604: return ("value=" + getValue() + ",visibleAmount=" + getVisibleAmount() 605: + ",minimum=" + getMinimum() + ",maximum=" + getMaximum() 606: + ",pageIncrement=" + pageIncrement + ",lineIncrement=" 607: + lineIncrement + ",orientation=" 608: + (orientation == HORIZONTAL ? "HORIZONTAL" : "VERTICAL") 609: + super.paramString()); 610: } 611: 612: /** 613: * Returns an array of all the objects currently registered as FooListeners 614: * upon this <code>Scrollbar</code>. FooListeners are registered using the 615: * addFooListener method. 616: * 617: * @exception ClassCastException If listenerType doesn't specify a class or 618: * interface that implements java.util.EventListener. 619: */ 620: public <T extends EventListener> T[] getListeners(Class<T> listenerType) 621: { 622: if (listenerType == AdjustmentListener.class) 623: return AWTEventMulticaster.getListeners(adjustment_listeners, 624: listenerType); 625: 626: return super.getListeners(listenerType); 627: } 628: 629: /** 630: * Returns an array of all registered adjustment listeners. 631: */ 632: public AdjustmentListener[] getAdjustmentListeners() 633: { 634: return (AdjustmentListener[]) getListeners(AdjustmentListener.class); 635: } 636: 637: /** 638: * Returns true if the value is in the process of changing. 639: * 640: * @since 1.4 641: */ 642: public boolean getValueIsAdjusting() 643: { 644: return valueIsAdjusting; 645: } 646: 647: /** 648: * Sets the value of valueIsAdjusting. 649: * 650: * @since 1.4 651: */ 652: public void setValueIsAdjusting(boolean valueIsAdjusting) 653: { 654: this.valueIsAdjusting = valueIsAdjusting; 655: } 656: 657: /** 658: * Generate a unique name for this scroll bar. 659: * 660: * @return A unique name for this scroll bar. 661: */ 662: String generateName() 663: { 664: return "scrollbar" + getUniqueLong(); 665: } 666: 667: private static synchronized long getUniqueLong() 668: { 669: return next_scrollbar_number++; 670: } 671: 672: /** 673: * This class provides accessibility support for the 674: * scrollbar. 675: * 676: * @author Jerry Quinn (jlquinn@optonline.net) 677: * @author Andrew John Hughes (gnu_andrew@member.fsf.org) 678: */ 679: protected class AccessibleAWTScrollBar extends AccessibleAWTComponent 680: implements AccessibleValue 681: { 682: /** 683: * Serialization constant to match JDK 1.5 684: */ 685: private static final long serialVersionUID = -344337268523697807L; 686: 687: /** 688: * Returns the role of this accessible object. 689: * 690: * @return the instance of <code>AccessibleRole</code>, 691: * which describes this object. 692: * 693: * @see javax.accessibility.AccessibleRole 694: */ 695: public AccessibleRole getAccessibleRole() 696: { 697: return AccessibleRole.SCROLL_BAR; 698: } 699: 700: /** 701: * Returns the state set of this accessible object. 702: * 703: * @return a set of <code>AccessibleState</code>s which 704: * represent the current state of the accessible object. 705: * 706: * @see javax.accessibility.AccessibleState 707: * @see javax.accessibility.AccessibleStateSet 708: */ 709: public AccessibleStateSet getAccessibleStateSet() 710: { 711: AccessibleStateSet states = super.getAccessibleStateSet(); 712: if (getOrientation() == HORIZONTAL) 713: states.add(AccessibleState.HORIZONTAL); 714: else 715: states.add(AccessibleState.VERTICAL); 716: if (getValueIsAdjusting()) 717: states.add(AccessibleState.BUSY); 718: return states; 719: } 720: 721: /** 722: * Returns an implementation of the <code>AccessibleValue</code> 723: * interface for this accessible object. In this case, the 724: * current instance is simply returned (with a more appropriate 725: * type), as it also implements the accessible value as well as 726: * the context. 727: * 728: * @return the accessible value associated with this context. 729: * 730: * @see javax.accessibility.AccessibleValue 731: */ 732: public AccessibleValue getAccessibleValue() 733: { 734: return this; 735: } 736: 737: /** 738: * Returns the current value of this accessible object. 739: * In this case, this is the same as the value for 740: * the scrollbar, wrapped in an <code>Integer</code> 741: * object. 742: * 743: * @return the numeric value of this scrollbar. 744: * 745: * @see javax.accessibility.AccessibleValue#getCurrentAccessibleValue() 746: */ 747: public Number getCurrentAccessibleValue() 748: { 749: return new Integer(getValue()); 750: } 751: 752: /** 753: * Sets the current value of this accessible object 754: * to that supplied. In this case, the value of the 755: * scrollbar is set, and this method always returns 756: * true. 757: * 758: * @param number the new accessible value. 759: * 760: * @return true if the value was set. 761: * 762: * @see javax.accessibility.AccessibleValue#setCurrentAccessibleValue(java.lang.Number) 763: */ 764: public boolean setCurrentAccessibleValue(Number number) 765: { 766: setValue(number.intValue()); 767: return true; 768: } 769: 770: /** 771: * Returns the minimum acceptable accessible value used 772: * by this object. In this case, this is the same as 773: * the minimum value of the scrollbar, wrapped in an 774: * object. 775: * 776: * @return the minimum value of this scrollbar. 777: * 778: * @see javax.accessibility.AccessibleValue#getMinimumAccessibleValue() 779: */ 780: public Number getMinimumAccessibleValue() 781: { 782: return new Integer(getMinimum()); 783: } 784: 785: /** 786: * Returns the maximum acceptable accessible value used 787: * by this object. In this case, this is the same as 788: * the maximum value of the scrollbar, wrapped in an 789: * object. 790: * 791: * @return the maximum value of this scrollbar. 792: * 793: * @see javax.accessibility.AccessibleValue#getMaximumAccessibleValue() 794: */ 795: public Number getMaximumAccessibleValue() 796: { 797: return new Integer(getMaximum()); 798: } 799: } 800: 801: /** 802: * Gets the AccessibleContext associated with this <code>Scrollbar</code>. 803: * The context is created, if necessary. 804: * 805: * @return the associated context 806: */ 807: public AccessibleContext getAccessibleContext() 808: { 809: /* Create the context if this is the first request */ 810: if (accessibleContext == null) 811: accessibleContext = new AccessibleAWTScrollBar(); 812: 813: return accessibleContext; 814: } 815: }