GNU Classpath (0.95) | |
Frames | No Frames |
1: /* JSlider.java -- 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: 39: package javax.swing; 40: 41: import java.awt.MenuContainer; 42: import java.awt.image.ImageObserver; 43: import java.beans.PropertyChangeEvent; 44: import java.io.Serializable; 45: import java.util.Dictionary; 46: import java.util.Enumeration; 47: import java.util.Hashtable; 48: 49: import javax.accessibility.Accessible; 50: import javax.accessibility.AccessibleContext; 51: import javax.accessibility.AccessibleRole; 52: import javax.accessibility.AccessibleState; 53: import javax.accessibility.AccessibleStateSet; 54: import javax.accessibility.AccessibleValue; 55: import javax.swing.event.ChangeEvent; 56: import javax.swing.event.ChangeListener; 57: import javax.swing.plaf.SliderUI; 58: import javax.swing.plaf.UIResource; 59: 60: /** 61: * A visual component that allows selection of a value within a 62: * range by adjusting a thumb in a track. The values for the minimum, 63: * maximum, extent and value are stored in a {@link 64: * DefaultBoundedRangeModel}. 65: * <p> 66: * A <code>JSlider</code> component has the following properties: 67: * </p> 68: * 69: * <table> 70: * <tr><th> Property </th><th> Stored in </th><th> Bound? </th></tr> 71: * <tr><td> extent </td><td> model </td><td> no </td></tr> 72: * <tr><td> inverted </td><td> slider </td><td> yes </td></tr> 73: * <tr><td> labelTable </td><td> slider </td><td> yes </td></tr> 74: * <tr><td> majorTickSpacing </td><td> slider </td><td> yes </td></tr> 75: * <tr><td> maximum </td><td> model </td><td> yes </td></tr> 76: * <tr><td> minimum </td><td> model </td><td> yes </td></tr> 77: * <tr><td> minorTickSpacing </td><td> slider </td><td> yes </td></tr> 78: * <tr><td> model </td><td> slider </td><td> yes </td></tr> 79: * <tr><td> orientation </td><td> slider </td><td> yes </td></tr> 80: * <tr><td> paintLabels </td><td> slider </td><td> yes </td></tr> 81: * <tr><td> paintTicks </td><td> slider </td><td> yes </td></tr> 82: * <tr><td> snapToTicks </td><td> slider </td><td> yes </td></tr> 83: * <tr><td> value </td><td> model </td><td> no </td></tr> 84: * <tr><td> valueIsAdjusting </td><td> model </td><td> no </td></tr> 85: * </table> 86: * 87: * <p> 88: * The various behavioural aspects of these properties follows: 89: * </p> 90: * 91: * <ul> 92: * <li> 93: * When a non-bound property stored in the slider changes, the slider fires 94: * a {@link ChangeEvent} to its change listeners. 95: * </li> 96: * <li> 97: * When a bound property stored in the slider changes, the slider fires a 98: * {@link PropertyChangeEvent} to its property change listeners. 99: * </li> 100: * <li> 101: * If any of the model's properties change, it fires a {@link ChangeEvent} to 102: * its listeners, which include the slider. 103: * </li> 104: * <li> 105: * If the slider receives a {@link ChangeEvent} from its model, it will 106: * propagate the event to its own change listeners, with the event's "source" 107: * property set to refer to the slider, rather than the model. 108: * </li> 109: * </ul> 110: */ 111: public class JSlider extends JComponent implements SwingConstants, Accessible, 112: ImageObserver, 113: MenuContainer, Serializable 114: { 115: 116: /** 117: * A little testing shows that the reference implementation creates 118: * labels from a class named LabelUIResource. 119: */ 120: private class LabelUIResource 121: extends JLabel 122: implements UIResource 123: { 124: LabelUIResource(String text, int align) 125: { 126: super(text, align); 127: setName("Slider.label"); 128: } 129: } 130: 131: private static final long serialVersionUID = -1441275936141218479L; 132: 133: /** 134: * Provides the accessibility features for the <code>JSlider</code> 135: * component. 136: */ 137: protected class AccessibleJSlider extends JComponent.AccessibleJComponent 138: implements AccessibleValue 139: { 140: private static final long serialVersionUID = -6301740148041106789L; 141: 142: /** 143: * Creates a new <code>AccessibleJSlider</code> instance. 144: */ 145: protected AccessibleJSlider() 146: { 147: // Nothing to do here. 148: } 149: 150: /** 151: * Returns a set containing the current state of the {@link JSlider} 152: * component. 153: * 154: * @return The accessible state set. 155: */ 156: public AccessibleStateSet getAccessibleStateSet() 157: { 158: AccessibleStateSet result = super.getAccessibleStateSet(); 159: if (orientation == JSlider.HORIZONTAL) 160: result.add(AccessibleState.HORIZONTAL); 161: else if (orientation == JSlider.VERTICAL) 162: result.add(AccessibleState.VERTICAL); 163: return result; 164: } 165: 166: /** 167: * Returns the accessible role for the <code>JSlider</code> component. 168: * 169: * @return {@link AccessibleRole#SLIDER}. 170: */ 171: public AccessibleRole getAccessibleRole() 172: { 173: return AccessibleRole.SLIDER; 174: } 175: 176: /** 177: * Returns an object that provides access to the current, minimum and 178: * maximum values for the {@link JSlider}. Since this class implements 179: * {@link AccessibleValue}, it returns itself. 180: * 181: * @return The accessible value. 182: */ 183: public AccessibleValue getAccessibleValue() 184: { 185: return this; 186: } 187: 188: /** 189: * Returns the current value of the {@link JSlider} component, as an 190: * {@link Integer}. 191: * 192: * @return The current value of the {@link JSlider} component. 193: */ 194: public Number getCurrentAccessibleValue() 195: { 196: return new Integer(getValue()); 197: } 198: 199: /** 200: * Sets the current value of the {@link JSlider} component and sends a 201: * {@link PropertyChangeEvent} (with the property name 202: * {@link AccessibleContext#ACCESSIBLE_VALUE_PROPERTY}) to all registered 203: * listeners. If the supplied value is <code>null</code>, this method 204: * does nothing and returns <code>false</code>. 205: * 206: * @param value the new slider value (<code>null</code> permitted). 207: * 208: * @return <code>true</code> if the slider value is updated, and 209: * <code>false</code> otherwise. 210: */ 211: public boolean setCurrentAccessibleValue(Number value) 212: { 213: if (value == null) 214: return false; 215: Number oldValue = getCurrentAccessibleValue(); 216: setValue(value.intValue()); 217: firePropertyChange(AccessibleContext.ACCESSIBLE_VALUE_PROPERTY, oldValue, 218: new Integer(getValue())); 219: return true; 220: } 221: 222: /** 223: * Returns the minimum value of the {@link JSlider} component, as an 224: * {@link Integer}. 225: * 226: * @return The minimum value of the {@link JSlider} component. 227: */ 228: public Number getMinimumAccessibleValue() 229: { 230: return new Integer(getMinimum()); 231: } 232: 233: /** 234: * Returns the maximum value of the {@link JSlider} component, as an 235: * {@link Integer}. 236: * 237: * @return The maximum value of the {@link JSlider} component. 238: */ 239: public Number getMaximumAccessibleValue() 240: { 241: return new Integer(getMaximum()); 242: } 243: } 244: 245: /** Whether or not this slider paints its ticks. */ 246: private transient boolean paintTicks; 247: 248: /** Whether or not this slider paints its track. */ 249: private transient boolean paintTrack = true; 250: 251: /** Whether or not this slider paints its labels. */ 252: private transient boolean paintLabels; 253: 254: /** 255: * A dictionary of (Integer, Component) pairs where each Component is a 256: * JLabel and the Integer determines where the label will be painted. 257: */ 258: private transient Dictionary labelTable; 259: 260: /** The model used to store the slider's range and current value. */ 261: protected BoundedRangeModel sliderModel; 262: 263: /** The space/distance between major ticks. */ 264: protected int majorTickSpacing; 265: 266: /** The space/distance between minor ticks. */ 267: protected int minorTickSpacing; 268: 269: /** Whether the slider snaps its values to ticks. */ 270: protected boolean snapToTicks; 271: 272: /** The orientation (horizontal or vertical) of the slider. */ 273: protected int orientation = HORIZONTAL; 274: 275: /** Whether the slider is inverted. */ 276: private transient boolean isInverted; 277: 278: /** 279: * The listener that monitors the slider's model and forwards events to the 280: * slider's listeners (see <code>createChangeListener()</code>). 281: */ 282: protected ChangeListener changeListener; 283: 284: /** The change event that is passed to all listeners of this slider. */ 285: protected transient ChangeEvent changeEvent; 286: 287: /** 288: * Creates a new horizontal <code>JSlider</code> instance with a minimum of 289: * 0, a maximum of 100, and a value of 50. 290: */ 291: public JSlider() 292: { 293: this(HORIZONTAL, 0, 100, 50); 294: } 295: 296: /** 297: * Creates a new <code>JSlider</code> instance with the given orientation 298: * and a minimum of 0, a maximum of 100, and a value of 50. 299: * 300: * @param orientation The orientation of the slider ({@link #HORIZONTAL} or 301: * {@link #VERTICAL}). 302: * 303: * @throws IllegalArgumentException if <code>orientation</code> is not one of 304: * the specified values. 305: */ 306: public JSlider(int orientation) 307: { 308: this(orientation, 0, 100, 50); 309: } 310: 311: /** 312: * Creates a new horizontal <code>JSlider</code> instance with the given 313: * maximum and minimum and a value that is halfway between the minimum and the 314: * maximum. 315: * 316: * @param minimum The minimum value. 317: * @param maximum The maximum value. 318: * 319: * @throws IllegalArgumentException if <code>minimum</code> is greater than 320: * <code>maximum</code>. 321: */ 322: public JSlider(int minimum, int maximum) 323: { 324: this(HORIZONTAL, minimum, maximum, (maximum + minimum) / 2); 325: } 326: 327: /** 328: * Creates a new horizontal <code>JSlider</code> instance with the given 329: * minimum, maximum, and value. 330: * 331: * @param minimum The minimum value. 332: * @param maximum The maximum value. 333: * @param value The initial value. 334: * 335: * @throws IllegalArgumentException if <code>value</code> is not in the 336: * specified range. 337: * @throws IllegalArgumentException if <code>minimum</code> is greater than 338: * <code>maximum</code>. 339: */ 340: public JSlider(int minimum, int maximum, int value) 341: { 342: this(HORIZONTAL, minimum, maximum, value); 343: } 344: 345: /** 346: * Creates a new <code>JSlider</code> instance with the given orientation, 347: * minimum, maximum, and value. 348: * 349: * @param orientation The orientation of the slider ({@link #HORIZONTAL} or 350: * {@link #VERTICAL}). 351: * @param minimum The minimum value of the JSlider. 352: * @param maximum The maximum value of the JSlider. 353: * @param value The initial value of the JSlider. 354: * 355: * @throws IllegalArgumentException if <code>orientation</code> is not one of 356: * the specified values. 357: * @throws IllegalArgumentException if <code>value</code> is not in the 358: * specified range. 359: * @throws IllegalArgumentException if <code>minimum</code> is greater than 360: * <code>maximum</code>. 361: */ 362: public JSlider(int orientation, int minimum, int maximum, int value) 363: { 364: sliderModel = new DefaultBoundedRangeModel(value, 0, minimum, maximum); 365: if (orientation != HORIZONTAL && orientation != VERTICAL) 366: throw new IllegalArgumentException(orientation 367: + " is not a legal orientation"); 368: this.orientation = orientation; 369: changeListener = createChangeListener(); 370: sliderModel.addChangeListener(changeListener); 371: updateUI(); 372: } 373: 374: /** 375: * Creates a new horizontal <code>JSlider</code> instance with the given 376: * model. 377: * 378: * @param model The model (<code>null</code> not permitted). 379: * 380: * @throws NullPointerException if <code>model</code> is <code>null</code>. 381: */ 382: public JSlider(BoundedRangeModel model) 383: { 384: sliderModel = model; 385: changeListener = createChangeListener(); 386: sliderModel.addChangeListener(changeListener); 387: updateUI(); 388: } 389: 390: /** 391: * Returns the slider's value (from the slider's model). 392: * 393: * @return The value of the slider. 394: * 395: * @see #setValue(int) 396: */ 397: public int getValue() 398: { 399: return sliderModel.getValue(); 400: } 401: 402: /** 403: * Sets the slider's value and sends a {@link ChangeEvent} to all 404: * registered listeners. Note that the model will fire a change event to all 405: * of its registered listeners first (with the model as the event source) and 406: * then the slider will fire another change event to all of its registered 407: * listeners (this time with the slider as the event source). 408: * 409: * @param value the new value. 410: * 411: * @see #getValue() 412: */ 413: public void setValue(int value) 414: { 415: sliderModel.setValue(value); 416: } 417: 418: /** 419: * Returns the slider's UI delegate. 420: * 421: * @return The slider's UI delegate. 422: */ 423: public SliderUI getUI() 424: { 425: return (SliderUI) ui; 426: } 427: 428: /** 429: * Sets the slider's UI delegate. 430: * 431: * @param ui the UI delegate. 432: */ 433: public void setUI(SliderUI ui) 434: { 435: super.setUI(ui); 436: } 437: 438: /** 439: * Sets this slider's UI delegate to the default (obtained from the 440: * {@link UIManager}) for the current look and feel. 441: */ 442: public void updateUI() 443: { 444: updateLabelUIs(); 445: setUI((SliderUI) UIManager.getUI(this)); 446: } 447: 448: /** 449: * Returns the suffix (<code>"SliderUI"</code> in this case) used to 450: * determine the class name for a UI delegate that can provide the look and 451: * feel for a <code>JSlider</code>. 452: * 453: * @return <code>"SliderUI"</code>. 454: */ 455: public String getUIClassID() 456: { 457: return "SliderUI"; 458: } 459: 460: /** 461: * Creates a {@link ChangeListener} that is added to the slider's model and 462: * forwards change events generated by the model to the listeners that are 463: * registered with the <code>JSlider</code> (by calling the 464: * {@link #fireStateChanged} method). 465: * 466: * @return A new listener. 467: */ 468: protected ChangeListener createChangeListener() 469: { 470: return new ChangeListener() 471: { 472: public void stateChanged(ChangeEvent ce) 473: { 474: // No need to trigger a repaint since the UI listens to the model 475: // as well. All we need to do is pass on the stateChanged event 476: // to our listeners. 477: fireStateChanged(); 478: } 479: }; 480: } 481: 482: /** 483: * Registers a listener with the slider so that it will receive 484: * {@link ChangeEvent} notifications. Note that change events generated 485: * by the slider's model will be forwarded automatically to the slider's 486: * listeners. 487: * 488: * @param listener the listener to register. 489: * 490: * @see #removeChangeListener(ChangeListener) 491: */ 492: public void addChangeListener(ChangeListener listener) 493: { 494: listenerList.add(ChangeListener.class, listener); 495: } 496: 497: /** 498: * Removes a listener from this slider so that it will no longer receive 499: * {@link ChangeEvent} notifications from the slider. 500: * 501: * @param listener The listener to remove. 502: * 503: * @see #addChangeListener(ChangeListener) 504: */ 505: public void removeChangeListener(ChangeListener listener) 506: { 507: listenerList.remove(ChangeListener.class, listener); 508: } 509: 510: /** 511: * Sends a {@link ChangeEvent} to all registered listeners, with this slider 512: * as the source. 513: */ 514: protected void fireStateChanged() 515: { 516: Object[] changeListeners = listenerList.getListenerList(); 517: if (changeEvent == null) 518: changeEvent = new ChangeEvent(this); 519: for (int i = changeListeners.length - 2; i >= 0; i -= 2) 520: { 521: if (changeListeners[i] == ChangeListener.class) 522: ((ChangeListener) changeListeners[i + 1]).stateChanged(changeEvent); 523: } 524: } 525: 526: /** 527: * Returns an array containing all the {@link ChangeListener} instances 528: * registered with this slider. If no listeners are registered, this method 529: * returns an empty array. 530: * 531: * @return An array array containing all the {@link ChangeListener} instances 532: * registered with this slider (possibly empty, but never 533: * <code>null</code>). 534: */ 535: public ChangeListener[] getChangeListeners() 536: { 537: return (ChangeListener[]) listenerList.getListeners(ChangeListener.class); 538: } 539: 540: /** 541: * Returns the slider's model, which stores the minimum, maximum and current 542: * values. 543: * 544: * @return The slider's model. 545: * 546: * @see #setModel(BoundedRangeModel) 547: */ 548: public BoundedRangeModel getModel() 549: { 550: return sliderModel; 551: } 552: 553: /** 554: * Sets the slider's model and sends a {@link PropertyChangeEvent} (with the 555: * property name "model") to all registered listeners. The change listener 556: * that the slider registered with the original model is removed and added 557: * to the new model (this ensures that {@link ChangeEvent} notifications 558: * generated by the model are automatically forwarded to listeners that are 559: * registered with the slider). 560: * 561: * @param model The model to use with the slider. 562: * 563: * @see #getModel() 564: */ 565: public void setModel(BoundedRangeModel model) 566: { 567: // I didn't do the null pointer check on purpose. 568: // If you try it with Sun's, it'll go ahead and set it to null 569: // and bork the next time it tries to access the model. 570: if (model != sliderModel) 571: { 572: BoundedRangeModel oldModel = sliderModel; 573: sliderModel = model; 574: oldModel.removeChangeListener(changeListener); 575: sliderModel.addChangeListener(changeListener); 576: firePropertyChange("model", oldModel, sliderModel); 577: } 578: } 579: 580: /** 581: * Returns the minimum value of the slider (from the slider's model). 582: * 583: * @return The minimum value of the slider. 584: * 585: * @see #setMinimum(int) 586: */ 587: public int getMinimum() 588: { 589: return sliderModel.getMinimum(); 590: } 591: 592: /** 593: * Sets the minimum value of the slider and fires a 594: * {@link PropertyChangeEvent} (with the property name "minimum") to all 595: * registered listeners. Note that: 596: * <p> 597: * <ul> 598: * <li>the minimum value is stored in the slider's model (see 599: * {@link #getModel()});</li> 600: * <li>in addition to the property change event, the slider also fires a 601: * {@link ChangeEvent}.</li> 602: * </ul> 603: * 604: * @param minimum The minimum value of the slider. 605: * 606: * @see #getMinimum() 607: */ 608: public void setMinimum(int minimum) 609: { 610: int old = sliderModel.getMinimum(); 611: sliderModel.setMinimum(minimum); 612: if (minimum != old) 613: firePropertyChange("minimum", old, minimum); 614: } 615: 616: /** 617: * Returns the slider's maximum value (obtained from the slider's model). 618: * 619: * @return The maximum value of the slider. 620: * 621: * @see #setMaximum(int) 622: */ 623: public int getMaximum() 624: { 625: return sliderModel.getMaximum(); 626: } 627: 628: /** 629: * Sets the maximum value of the slider and fires a 630: * {@link PropertyChangeEvent} (with the property name "maximum") to all 631: * registered listeners. Note that: 632: * <p> 633: * <ul> 634: * <li>the maximum value is stored in the slider's model (see 635: * {@link #getModel()});</li> 636: * <li>in addition to the property change event, the slider also fires a 637: * {@link ChangeEvent}.</li> 638: * </ul> 639: * 640: * @param maximum The maximum value of the slider. 641: * 642: * @see #getMaximum() 643: */ 644: public void setMaximum(int maximum) 645: { 646: int old = sliderModel.getMaximum(); 647: sliderModel.setMaximum(maximum); 648: if (maximum != old) 649: firePropertyChange("maximum", old, maximum); 650: } 651: 652: /** 653: * Returns the <code>valueIsAdjusting</code> flag from the slider's model. 654: * 655: * @return The <code>valueIsAdjusting</code> flag from the slider's model. 656: * 657: * @see #setValueIsAdjusting(boolean) 658: */ 659: public boolean getValueIsAdjusting() 660: { 661: return sliderModel.getValueIsAdjusting(); 662: } 663: 664: /** 665: * Sets the <code>valueIsAdjusting</code> flag in the slider's model, and 666: * sends a {@link ChangeEvent} to all registered listeners. 667: * 668: * @param adjusting the new flag value. 669: * 670: * @see #getValueIsAdjusting() 671: */ 672: public void setValueIsAdjusting(boolean adjusting) 673: { 674: sliderModel.setValueIsAdjusting(adjusting); 675: } 676: 677: /** 678: * Returns the slider's extent value, obtained from the slider's model. 679: * 680: * @return The extent value. 681: * 682: * @see #setExtent(int) 683: */ 684: public int getExtent() 685: { 686: return sliderModel.getExtent(); 687: } 688: 689: /** 690: * Sets the slider's extent value and sends a {@link ChangeEvent} to all 691: * registered listeners. Note that the model will fire a change event to all 692: * of its registered listeners first (with the model as the event source) and 693: * then the slider will fire another change event to all of its registered 694: * listeners (this time with the slider as the event source). 695: * 696: * @param extent The extent value for this slider. 697: * 698: * @see #getExtent() 699: */ 700: public void setExtent(int extent) 701: { 702: sliderModel.setExtent(extent); 703: } 704: 705: /** 706: * Returns the orientation of the slider, either {@link JSlider#HORIZONTAL} 707: * or {@link JSlider#VERTICAL}. 708: * 709: * @return The orientation of the slider. 710: * 711: * @see #setOrientation(int) 712: */ 713: public int getOrientation() 714: { 715: return orientation; 716: } 717: 718: /** 719: * Sets the orientation for the slider and sends a 720: * {@link PropertyChangeEvent} (with the property name "orientation") to all 721: * registered listeners. 722: * 723: * @param orientation the orientation (one of {@link JSlider#HORIZONTAL} or 724: * {@link JSlider#VERTICAL}). 725: * 726: * @throws IllegalArgumentException if <code>orientation</code> is not one of 727: * the permitted values. 728: * 729: * @see #getOrientation() 730: */ 731: public void setOrientation(int orientation) 732: { 733: if (orientation != VERTICAL && orientation != HORIZONTAL) 734: throw new IllegalArgumentException( 735: "orientation must be one of: VERTICAL, HORIZONTAL"); 736: if (orientation != this.orientation) 737: { 738: int oldOrientation = this.orientation; 739: this.orientation = orientation; 740: firePropertyChange("orientation", oldOrientation, this.orientation); 741: revalidate(); 742: } 743: } 744: 745: /** 746: * Returns the label table for the slider. 747: * 748: * @return The label table for the slider (possibly <code>null</code>). 749: * 750: * @see #setLabelTable(Dictionary) 751: */ 752: public Dictionary getLabelTable() 753: { 754: return labelTable; 755: } 756: 757: /** 758: * Sets the table of labels for the slider and sends a 759: * {@link PropertyChangeEvent} (with the property name "labelTable") to all 760: * registered listeners. 761: * 762: * @param table the table of labels (<code>null</code> permitted). 763: * 764: * @see #getLabelTable() 765: */ 766: public void setLabelTable(Dictionary table) 767: { 768: if (table != labelTable) 769: { 770: Dictionary oldTable = labelTable; 771: labelTable = table; 772: updateLabelUIs(); 773: firePropertyChange("labelTable", oldTable, labelTable); 774: revalidate(); 775: repaint(); 776: } 777: } 778: 779: /** 780: * Resets the UI delegates for the labels in the <code>labelTable</code> to 781: * the default for the current look and feel. 782: */ 783: protected void updateLabelUIs() 784: { 785: if (labelTable != null) 786: { 787: for (Enumeration list = labelTable.elements(); list.hasMoreElements();) 788: { 789: Object o = list.nextElement(); 790: if (o instanceof JComponent) 791: { 792: JComponent jc = (JComponent) o; 793: jc.updateUI(); 794: jc.setSize(jc.getPreferredSize()); 795: } 796: } 797: } 798: } 799: 800: /** 801: * Creates a hashtable of <code>(Integer, JLabel)</code> pairs that can be 802: * used as a label table for this slider. The labels will start from the 803: * slider's minimum and increase by the increment. Each label will have a text 804: * string indicating its integer value. 805: * 806: * @param increment The increment between labels (must be > 0). 807: * 808: * @return A hashtable containing the labels. 809: * 810: * @throws IllegalArgumentException if <code>increment</code> is not greater 811: * than zero. 812: */ 813: public Hashtable createStandardLabels(int increment) 814: { 815: return createStandardLabels(increment, sliderModel.getMinimum()); 816: } 817: 818: /** 819: * Creates a hashtable of <code>(Integer, JLabel)</code> pairs that can be 820: * used as a label table for this slider. The labels will start from the 821: * given start value and increase by the increment. Each label will have a 822: * text string indicating its integer value. 823: * 824: * @param increment The increment between labels (must be > 0). 825: * @param start The value to start from. 826: * 827: * @return A hashtable with the labels and their keys. 828: * 829: * @throws IllegalArgumentException if <code>increment</code> is not greater 830: * than zero, or <code>start</code> is not within the range of the 831: * model. 832: */ 833: public Hashtable createStandardLabels(int increment, int start) 834: { 835: if (increment <= 0) 836: throw new IllegalArgumentException("Requires 'increment' > 0."); 837: if (start < getMinimum() || start > getMaximum()) 838: throw new IllegalArgumentException("The 'start' value is out of range."); 839: Hashtable table = new Hashtable(); 840: int max = getMaximum(); 841: for (int i = start; i <= max; i += increment) 842: { 843: LabelUIResource label = new LabelUIResource(String.valueOf(i), 844: JLabel.CENTER); 845: table.put(new Integer(i), label); 846: } 847: return table; 848: } 849: 850: /** 851: * Returns the flag that controls whether or not the value scale for the 852: * slider is inverted (the default value is <code>false</code>). 853: * 854: * @return The flag that controls whether or not the value scale for the 855: * slider is inverted. 856: * 857: * @see #setInverted(boolean) 858: */ 859: public boolean getInverted() 860: { 861: return isInverted; 862: } 863: 864: /** 865: * Sets the flag that controls whether or not the value scale for the 866: * slider is inverted and, if the new flag value is different to the old flag 867: * value, sends a {@link PropertyChangeEvent} to all registered listeners. 868: * Typically, a horizontal slider will display a scale that increases from 869: * left to right, but this is reversed if the 'inverted' flag is set to 870: * <code>true</code>. Similarly, a vertical slider will display a scale that 871: * increases from bottom to top, and this is reversed if the 'inverted' flag 872: * is set to <code>true</code>. 873: * 874: * @param inverted the new flag value. 875: * 876: * @see #getInverted() 877: */ 878: public void setInverted(boolean inverted) 879: { 880: if (isInverted != inverted) 881: { 882: boolean oldInverted = isInverted; 883: isInverted = inverted; 884: firePropertyChange("inverted", oldInverted, isInverted); 885: repaint(); 886: } 887: } 888: 889: /** 890: * Returns the distance between major tick marks along the slider's value 891: * scale. 892: * 893: * @return The amount of units between each major tick mark. 894: * 895: * @see #setMajorTickSpacing(int) 896: */ 897: public int getMajorTickSpacing() 898: { 899: return majorTickSpacing; 900: } 901: 902: /** 903: * Sets the distance between major tick marks along the slider's value scale, 904: * and sends a {@link PropertyChangeEvent} (with the property name 905: * "majorTickSpacing") to all registered listeners. 906: * 907: * @param spacing the distance between major tick marks. 908: * 909: * @see #getMajorTickSpacing() 910: */ 911: public void setMajorTickSpacing(int spacing) 912: { 913: if (majorTickSpacing != spacing) 914: { 915: int oldSpacing = majorTickSpacing; 916: majorTickSpacing = spacing; 917: if (labelTable == null && majorTickSpacing > 0 && getPaintLabels()) 918: setLabelTable(createStandardLabels(majorTickSpacing)); 919: firePropertyChange("majorTickSpacing", oldSpacing, majorTickSpacing); 920: if (getPaintTicks()) 921: repaint(); 922: } 923: } 924: 925: /** 926: * Returns the distance between minor tick marks along the slider's value 927: * scale. 928: * 929: * @return The distance between minor tick marks along the slider's value 930: * scale. 931: * 932: * @see #setMinorTickSpacing(int) 933: */ 934: public int getMinorTickSpacing() 935: { 936: return minorTickSpacing; 937: } 938: 939: /** 940: * Sets the distance between minor tick marks along the slider's value scale, 941: * and sends a {@link PropertyChangeEvent} (with the property name 942: * "minorTickSpacing") to all registered listeners. 943: * 944: * @param spacing the distance between minor tick marks. 945: * 946: * @see #getMinorTickSpacing() 947: */ 948: public void setMinorTickSpacing(int spacing) 949: { 950: if (minorTickSpacing != spacing) 951: { 952: int oldSpacing = minorTickSpacing; 953: minorTickSpacing = spacing; 954: firePropertyChange("minorTickSpacing", oldSpacing, minorTickSpacing); 955: if (getPaintTicks()) 956: repaint(); 957: } 958: } 959: 960: /** 961: * Returns the flag that controls whether the slider thumb will snap to ticks. 962: * Sliders that snap to ticks will automatically move the thumb to the 963: * nearest tick mark. 964: * 965: * @return <code>true</code> if the slider thumb automatically. 966: * 967: * @see #setSnapToTicks(boolean) 968: */ 969: public boolean getSnapToTicks() 970: { 971: return snapToTicks; 972: } 973: 974: /** 975: * Sets the flag that controls whether the slider thumb will snap to ticks 976: * and sends a {@link PropertyChangeEvent} (with the property name 977: * 'snapToTicks') to all registered listeners. Sliders that snap to ticks 978: * will automatically move the thumb to the nearest tick mark. 979: * 980: * @param snap the new flag value. 981: * 982: * @see #getSnapToTicks() 983: */ 984: public void setSnapToTicks(boolean snap) 985: { 986: if (snap != snapToTicks) 987: { 988: snapToTicks = snap; 989: firePropertyChange("snapToTicks", !snap, snap); 990: } 991: } 992: 993: /** 994: * Returns the flag that controls whether or not tick marks are painted along 995: * the slider's value scale. 996: * 997: * @return <code>true</code> if tick marks should be painted, and 998: * <code>false</code> if tick marks should not be painted. 999: * 1000: * @see #setPaintTicks(boolean) 1001: */ 1002: public boolean getPaintTicks() 1003: { 1004: return paintTicks; 1005: } 1006: 1007: /** 1008: * Sets the flag that controls whether or not tick marks are painted along 1009: * the slider's value scale, and sends a {@link PropertyChangeEvent} (with 1010: * the property name "paintTicks") to all registered listeners. In 1011: * addition to setting this property to <code>true</code>, one or both of the 1012: * minor tick spacing and major tick spacing attributes must be set to a 1013: * value greater than 0 in order for ticks to be painted. 1014: * 1015: * @param paint Whether ticks will be painted. 1016: * 1017: * @see #getPaintTicks() 1018: */ 1019: public void setPaintTicks(boolean paint) 1020: { 1021: if (paint != paintTicks) 1022: { 1023: boolean oldPaintTicks = paintTicks; 1024: paintTicks = paint; 1025: firePropertyChange("paintTicks", oldPaintTicks, paintTicks); 1026: revalidate(); 1027: repaint(); 1028: } 1029: } 1030: 1031: /** 1032: * Returns the flag that controls whether or not the track is painted. 1033: * 1034: * @return Whether the track will be painted. 1035: * 1036: * @see #setPaintTrack(boolean) 1037: */ 1038: public boolean getPaintTrack() 1039: { 1040: return paintTrack; 1041: } 1042: 1043: /** 1044: * Sets the flag that controls whether or not the track is painted, and 1045: * sends a {@link PropertyChangeEvent} (for the "paintTrack" property) to all 1046: * registered listeners. 1047: * 1048: * @param paint Whether the track will be painted. 1049: * 1050: * @see #getPaintTrack() 1051: */ 1052: public void setPaintTrack(boolean paint) 1053: { 1054: if (paintTrack != paint) 1055: { 1056: paintTrack = paint; 1057: firePropertyChange("paintTrack", !paint, paint); 1058: repaint(); 1059: } 1060: } 1061: 1062: /** 1063: * Returns the flag that controls whether or not labels are painted for the 1064: * tick marks along the slider. 1065: * 1066: * @return Whether labels will be painted. 1067: * 1068: * @see #setPaintLabels(boolean) 1069: */ 1070: public boolean getPaintLabels() 1071: { 1072: return paintLabels; 1073: } 1074: 1075: /** 1076: * Sets the flag that controls whether or not labels are painted for the 1077: * tick marks along the slider and sends a {@link PropertyChangeEvent} (with 1078: * the property name "paintLabels") to all registered listeners. 1079: * 1080: * @param paint Whether labels will be painted. 1081: * 1082: * @see #getPaintLabels() 1083: */ 1084: public void setPaintLabels(boolean paint) 1085: { 1086: if (paint != paintLabels) 1087: { 1088: paintLabels = paint; 1089: if (paint && majorTickSpacing > 0 && labelTable == null) 1090: setLabelTable(createStandardLabels(majorTickSpacing)); 1091: firePropertyChange("paintLabels", !paint, paint); 1092: revalidate(); 1093: repaint(); 1094: } 1095: } 1096: 1097: /** 1098: * Returns an implementation-dependent string describing the attributes of 1099: * this <code>JSlider</code>. 1100: * 1101: * @return A string describing the attributes of this <code>JSlider</code> 1102: * (never <code>null</code>). 1103: */ 1104: protected String paramString() 1105: { 1106: String superParamStr = super.paramString(); 1107: StringBuffer sb = new StringBuffer(); 1108: sb.append(",isInverted=").append(getInverted()); 1109: sb.append(",majorTickSpacing=").append(getMajorTickSpacing()); 1110: sb.append(",minorTickSpacing=").append(getMinorTickSpacing()); 1111: sb.append(",orientation="); 1112: if (orientation == HORIZONTAL) 1113: sb.append("HORIZONTAL"); 1114: else 1115: sb.append("VERTICAL"); 1116: sb.append(",paintLabels=").append(getPaintLabels()); 1117: sb.append(",paintTicks=").append(getPaintTicks()); 1118: sb.append(",paintTrack=").append(getPaintTrack()); 1119: sb.append(",snapToTicks=").append(getSnapToTicks()); 1120: 1121: // the following is output by the reference implementation. We don't 1122: // strictly need to replicate this. Perhaps it has some meaning, but 1123: // I couldn't determine it yet... 1124: sb.append(",snapToValue=true"); 1125: 1126: return superParamStr + sb.toString(); 1127: } 1128: 1129: /** 1130: * Returns the object that provides accessibility features for this 1131: * <code>JSlider</code> component. 1132: * 1133: * @return The accessible context (an instance of {@link AccessibleJSlider}). 1134: */ 1135: public AccessibleContext getAccessibleContext() 1136: { 1137: if (accessibleContext == null) 1138: accessibleContext = new AccessibleJSlider(); 1139: 1140: return accessibleContext; 1141: } 1142: }
GNU Classpath (0.95) |