home *** CD-ROM | disk | FTP | other *** search
Java Source | 1998-03-20 | 27.2 KB | 913 lines |
- /*
- * @(#)JSlider.java 1.58 98/02/04
- *
- * Copyright (c) 1997 Sun Microsystems, Inc. All Rights Reserved.
- *
- * This software is the confidential and proprietary information of Sun
- * Microsystems, Inc. ("Confidential Information"). You shall not
- * disclose such Confidential Information and shall use it only in
- * accordance with the terms of the license agreement you entered into
- * with Sun.
- *
- * SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF THE
- * SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
- * PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR ANY DAMAGES
- * SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING
- * THIS SOFTWARE OR ITS DERIVATIVES.
- *
- */
-
- package java.awt.swing;
-
- import java.awt.swing.border.*;
- import java.awt.swing.event.*;
- import java.awt.swing.plaf.*;
- import java.awt.accessibility.*;
-
- import java.io.Serializable;
- import java.util.*;
-
-
- /**
- * A component that lets the user graphically select a value by slding
- * a knob within a bounded interval. The slider can show both
- * major tick marks and minor tick marks between them. The number of
- * pixels between the tick marks is controlled with
- * <code>setMajorTickSpacing</code> and <code>setMinorTickSpacing</code>.
- * <p>
- * Warning: serialized objects of this class will not be compatible with
- * future swing releases. The current serialization support is appropriate
- * for short term storage or RMI between Swing1.0 applications. It will
- * not be possible to load serialized Swing1.0 objects with future releases
- * of Swing. The JDK1.2 release of Swing will be the compatibility
- * baseline for the serialized form of Swing objects.
- *
- * @beaninfo
- * attribute: isContainer false
- * description: A component that supports selecting a integer value from a range.
- *
- * @version 1.58 02/04/98
- * @author David Kloba
- */
- public class JSlider extends JComponent implements SwingConstants, Accessible
- {
- /**
- * The data model that handles the numeric maximum value,
- * minimum value, and current-position value for the slider.
- */
- protected BoundedRangeModel sliderModel;
-
- /**
- * The number of pixels between the major tick marks -- the
- * larger marks that break up the minor tick marks.
- */
- protected int majorTickSpacing;
-
- /**
- * The number of pixels between the minor tick marks -- the
- * smaller marks that occur between the major tick marks.
- * @see #setMinorTickSpacing
- */
- protected int minorTickSpacing;
-
- /**
- * If true, the knob (and the data value it represents)
- * resolve to the closest tick mark next to where the user
- * positioned the knob.
- * @see #setSnapToTicks
- */
- protected boolean snapToTicks = true;
-
- private boolean paintTicks = false;
- private boolean paintLabels = false;
- private boolean isInverted = false;
-
-
- /**
- * @see #setOrientation
- */
- protected int orientation;
-
-
- /**
- * Whether the component fully paints all of the pixels in its
- * region. By default this component is not transparent, so the
- * value is true. Use <code>setOpaque</code> to make the sliders
- * background transparent, so that pixels under the slider
- * "show through" in the area the knob moves in.
- */
- private Dictionary labelTable;
-
-
- /**
- * The changeListener (no suffix) is the listener we add to the
- * Sliders model. By default this listener just forwards events
- * to ChangeListeners (if any) added directly to the slider.
- *
- * @see #addChangeListener
- * @see #createChangeListener
- */
- protected ChangeListener changeListener = createChangeListener();
-
-
- /**
- * Only one ChangeEvent is needed per slider instance since the
- * event's only (read-only) state is the source property. The source
- * of events generated here is always "this". The event is lazily
- * created the first time that an event notification is fired.
- *
- * @see #fireStateChanged
- */
- protected transient ChangeEvent changeEvent = null;
-
-
- private void checkOrientation(int orientation) {
- switch (orientation) {
- case VERTICAL:
- case HORIZONTAL:
- break;
- default:
- throw new IllegalArgumentException("orientation must be one of: VERTICAL, HORIZONTAL");
- }
- }
-
-
- /**
- * Creates a slider with the specified orientation and the
- * specified mimimum, maximum, and initial values.
- *
- * @exception IllegalArgumentException if orientation is not one of VERTICAL, HORIZONTAL
- *
- * @see #setOrientation
- * @see #setMinimum
- * @see #setMaximum
- * @see #setValue
- */
- public JSlider(int orientation, int min, int max, int value)
- {
- checkOrientation(orientation);
- this.orientation = orientation;
- sliderModel = new DefaultBoundedRangeModel(value, 0, min, max);
- sliderModel.addChangeListener(changeListener);
- updateUI();
- }
-
-
- /**
- * Creates a horizontal slider with the range 0 to 100 and
- * an intitial value of 50.
- */
- public JSlider() {
- this(HORIZONTAL, 0, 100, 50);
- }
-
-
- /**
- * Gets the UI object which implements the L&F for this component.
- *
- * @return the SliderUI object that implements the Slider L&F
- */
- public SliderUI getUI() {
- return (SliderUI)ui;
- }
-
-
- /**
- * Sets the UI object which implements the L&F for this component.
- *
- * @param ui the SliderUI L&F object
- * @see UIDefaults#getUI
- * @beaninfo
- * bound: true
- * hidden: true
- * description: The UI object that implements the slider's LookAndFeel.
- */
- public void setUI(SliderUI ui) {
- super.setUI(ui);
- }
-
-
- /**
- * Notification from the UIFactory that the L&F has changed.
- * Called to replace the UI with the latest version from the
- * default UIFactory.
- *
- * @see JComponent#updateUI
- */
- public void updateUI() {
- updateLabelUIs();
- setUI((SliderUI)UIManager.getUI(this));
- }
-
-
- /**
- * Returns the name of the L&F class that renders this component.
- *
- * @return "SliderUI"
- * @see JComponent#getUIClassID
- * @see UIDefaults#getUI
- */
- public String getUIClassID() {
- return "SliderUI";
- }
-
-
- /**
- * We pass Change events along to the listeners with the
- * the slider (instead of the model itself) as the event source.
- */
- private class ModelListener implements ChangeListener, Serializable {
- public void stateChanged(ChangeEvent e) {
- fireStateChanged();
- }
- }
-
-
- /**
- * Subclasses that want to handle model ChangeEvents differently
- * can override this method to return their own ChangeListener
- * implementation. The default ChangeListener just forwards
- * ChangeEvents to the ChangeListeners added directly to the slider.
- *
- * @see #fireStateChanged
- */
- protected ChangeListener createChangeListener() {
- return new ModelListener();
- }
-
-
- /**
- * Adds a ChangeListener to the slider.
- *
- * @param l the ChangeListener to add
- * @see #fireStateChanged
- * @see #removeChangeListener
- */
- public void addChangeListener(ChangeListener l) {
- listenerList.add(ChangeListener.class, l);
- }
-
-
- /**
- * Removes a ChangeListener from the slider.
- *
- * @param l the ChangeListener to remove
- * @see #fireStateChanged
- * @see #addChangeListener
-
- */
- public void removeChangeListener(ChangeListener l) {
- listenerList.remove(ChangeListener.class, l);
- }
-
-
- /**
- * Send a ChangeEvent, whose source is this Slider, to
- * each listener. This method method is called each time
- * a ChangeEvent is received from the model.
- *
- * @see #addChangeListener
- * @see EventListenerList
- */
- protected void fireStateChanged() {
- Object[] listeners = listenerList.getListenerList();
- for (int i = listeners.length - 2; i >= 0; i -= 2) {
- if (listeners[i]==ChangeListener.class) {
- if (changeEvent == null) {
- changeEvent = new ChangeEvent(this);
- }
- ((ChangeListener)listeners[i+1]).stateChanged(changeEvent);
- }
- }
- }
-
-
- /**
- * Returns data model that handles the sliders three
- * fundamental properties: minimum, maximum, value.
- *
- * @see #setModel
- */
- public BoundedRangeModel getModel() {
- return sliderModel;
- }
-
-
- /**
- * Sets the model that handles the sliders three
- * fundamental properties: minimum, maximum, value.
- *
- * @see #getModel
- * @beaninfo
- * bound: true
- * description: The sliders BoundedRangeModel.
- */
- public void setModel(BoundedRangeModel newModel)
- {
- BoundedRangeModel oldModel = getModel();
-
- if (oldModel != null) {
- oldModel.removeChangeListener(changeListener);
- }
-
- sliderModel = newModel;
-
- if (newModel != null) {
- newModel.addChangeListener(changeListener);
-
- if (accessibleContext != null) {
- accessibleContext.firePropertyChange(
- AccessibleContext.ACCESSIBLE_VALUE_PROPERTY,
- (oldModel == null
- ? null : new Integer(oldModel.getValue())),
- (newModel == null
- ? null : new Integer(newModel.getValue())));
- }
- }
-
- firePropertyChange("model", oldModel, sliderModel);
- }
-
-
- /**
- * Returns the sliders value.
- * @return the models value property
- * @see #setValue
- */
- public int getValue() {
- return getModel().getValue();
- }
-
-
- /**
- * Sets the sliders current value. This method just forwards
- * the value to the model.
- *
- * @see #getValue
- * @beaninfo
- * preferred: true
- * description: The sliders current value.
- */
- public void setValue(int n) {
- BoundedRangeModel m = getModel();
- int oldValue = m.getValue();
- m.setValue(n);
-
- if (accessibleContext != null) {
- accessibleContext.firePropertyChange(
- AccessibleContext.ACCESSIBLE_VALUE_PROPERTY,
- new Integer(oldValue),
- new Integer(m.getValue()));
- }
- }
-
-
- /**
- * Returns the minimum value supported by the slider.
- *
- * @return the value of the models minimum property
- * @see #setMinimum
- */
- public int getMinimum() {
- return getModel().getMinimum();
- }
-
-
- /**
- * Sets the models minimum property.
- *
- * @see #getMinimum
- * @see BoundedRangeModel#setMinimum
- * @beaninfo
- * preferred: true
- * description: The sliders minimum value.
- */
- public void setMinimum(int minimum) {
- getModel().setMinimum(minimum);
- }
-
-
- /**
- * Returns the maximum value supported by the slider.
- *
- * @return the value of the models maximum property
- * @see #setMaximum
- */
- public int getMaximum() {
- return getModel().getMaximum();
- }
-
-
- /**
- * Sets the models maximum property.
- *
- * @see #getMaximum
- * @see BoundedRangeModel#setMaximum
- * @beaninfo
- * preferred: true
- * description: The sliders maximum value.
- */
- public void setMaximum(int maximum) {
- getModel().setMaximum(maximum);
- }
-
-
- /**
- * True if the slider knob is being dragged.
- *
- * @return the value of the models valueIsAdjusting property
- * @see #setValueIsAdjusting
- */
- public boolean getValueIsAdjusting() {
- return getModel().getValueIsAdjusting();
- }
-
-
- /**
- * Sets the models valueIsAdjusting property. Slider look and
- * feel implementations should set this property to true when
- * a knob drag begins, and to false when the drag ends. The
- * slider model will not generate ChangeEvents while
- * valueIsAdjusting is true.
- *
- * @see #getValueIsAdjusting
- * @see BoundedRangeModel#setValueIsAdjusting
- * @beaninfo
- * expert: true
- * description: True if the slider knob is being dragged.
- */
- public void setValueIsAdjusting(boolean b) {
- BoundedRangeModel m = getModel();
- boolean oldValue = m.getValueIsAdjusting();
- m.setValueIsAdjusting(b);
-
- if ((oldValue != b) && (accessibleContext != null)) {
- accessibleContext.firePropertyChange(
- AccessibleContext.ACCESSIBLE_STATE_PROPERTY,
- ((oldValue) ? AccessibleState.BUSY : null),
- ((b) ? AccessibleState.BUSY : null));
- }
- }
-
-
- /**
- * @return the range of values "covered" by the knob.
- * @see #setExtent
- * @see BoundedRangeModel#getExtent
- */
- public int getExtent() {
- return getModel().getExtent();
- }
-
-
- /**
- * Sets the size of the range "covered" by the knob. Most look
- * and feel implementations will change the value by this amount
- * if the user clicks on either side of the knob.
- *
- * @see #getExtent
- * @see BoundedRangeModel#setExtent
- * @beaninfo
- * expert: true
- * description: Size of the range covered by the knob.
- */
- public void setExtent(int extent) {
- getModel().setExtent(extent);
- }
-
-
- /**
- * @return VERTICAL or HORIZONTAL
- * @see #setOrientation
- */
- public int getOrientation() {
- return orientation;
- }
-
-
- /**
- * Set the scrollbars orientation to either VERTICAL or HORIZONTAL.
- *
- * @exception IllegalArgumentException if orientation is not one of VERTICAL, HORIZONTAL
- * @see #getOrientation
- * @beaninfo
- * preferred: true
- * bound: true
- * description: Set the scrollbars orientation to either VERTICAL or HORIZONTAL.
- * enum: VERTICAL JSlider.VERTICAL
- * HORIZONTAL JSlider.HORIZONTAL
- *
- */
- public void setOrientation(int orientation)
- {
- checkOrientation(orientation);
- int oldValue = orientation;
- this.orientation = orientation;
- firePropertyChange("orientation", oldValue, orientation);
-
- if ((oldValue != orientation) && (accessibleContext != null)) {
- accessibleContext.firePropertyChange(
- AccessibleContext.ACCESSIBLE_STATE_PROPERTY,
- ((oldValue == VERTICAL)
- ? AccessibleState.VERTICAL : AccessibleState.HORIZONTAL),
- ((orientation == VERTICAL)
- ? AccessibleState.VERTICAL : AccessibleState.HORIZONTAL));
- }
- }
-
-
-
- /**
- * Returns the dictionary of what labels to draw at which values.
- *
- * @return the Dictionary containing labels and where to draw them
- */
- public Dictionary getLabelTable() {
- /*
- if ( labelTable == null && getMajorTickSpacing() > 0 ) {
- setLabelTable( createStandardLabels( getMajorTickSpacing() ) );
- }
- */
- return labelTable;
- }
-
-
- /**
- * Used to specify what label will be drawn at any given value.
- * The key-value pairs are of this format: <B>{ Integer value, java.awt.Component label }</B>
- *
- * @see #createStandardLabels
- * @see #getLabelTable
- * @beaninfo
- * hidden: true
- * bound: true
- * description: Specifies what labels will be drawn for any given value.
- */
- public void setLabelTable( Dictionary labels ) {
- Dictionary oldTable = labelTable;
- labelTable = labels;
- updateLabelUIs();
- firePropertyChange("labelTable", oldTable, labelTable );
- }
-
-
- /**
- * Called internally to replace the label UIs with the latest versions
- * from the UIFactory when the UIFactory notifies us via
- * <code>updateUI</code> that the L&F has changed.
- *
- * @see JComponent#updateUI
- */
- protected void updateLabelUIs() {
- if ( getLabelTable() == null ) {
- return;
- }
- Enumeration labels = getLabelTable().keys();
- while ( labels.hasMoreElements() ) {
- Object value = getLabelTable().get( labels.nextElement() );
- if ( value instanceof JComponent ) {
- JComponent component = (JComponent)value;
- component.updateUI();
- component.setSize( component.getPreferredSize() );
- }
- }
- }
-
-
- /**
- * Creates a hashtable that will draw text labels starting at the slider minimum using the
- * increment specified. If you call createStandardLabels( 10 ) and the slider minimum is
- * zero, then it will make labels for the values 0, 10, 20, 30, and so on.
- * @see #setLabelTable
- */
- public Hashtable createStandardLabels( int increment ) {
- return createStandardLabels( increment, getMinimum() );
- }
-
-
- /**
- * Creates a hashtable that will draw text labels starting at the start point
- * specified using the increment specified. If you call createStandardLabels( 10, 2 ),
- * then it will make labels for the values 2, 12, 22, 32, and so on.
- * @see #setLabelTable
- */
- public Hashtable createStandardLabels( int increment, int start ) {
- if ( start > getMaximum() || start < getMinimum() ) {
- throw new IllegalArgumentException( "Slider label start point out of range." );
- }
-
- Hashtable table = new Hashtable();
-
- for ( int labelIndex = start; labelIndex <= getMaximum(); labelIndex += increment ) {
- table.put( new Integer( labelIndex ), new JLabel( ""+labelIndex, JLabel.CENTER ) );
- }
-
- return table;
- }
-
-
- /**
- * Returns true if the value-range shown for the slider is reversed,
- * with the maximum value at the left end of a horizontal slider or
- * at the bottom of a vertical one.
- *
- * @return true if the slider values are reversed from their normal order
- */
- public boolean getInverted() {
- return isInverted;
- }
-
-
- /**
- * Specify true to reverse the value-range shown for the slider so that
- * the maximum value is at the left end of a horizontal slider or
- * at the bottom of a vertical one. Specify false to put the value range
- * in the normal order.
- *
- * @param b true to reverse the slider values from their normal order
- * @beaninfo
- * bound: true
- * description: If true reverses the slider values from their normal order
- *
- */
- public void setInverted( boolean b ) {
- boolean oldValue = isInverted;
- isInverted = b;
- firePropertyChange("inverted", oldValue, isInverted);
- }
-
-
- /**
- * @return the number of pixels between major ticks
- * @see #setMajorTickSpacing
- */
- public int getMajorTickSpacing() {
- return majorTickSpacing;
- }
-
-
- /**
- * Sets the number of pixels between major tick marks.
- * @see #getMajorTickSpacing
- * @beaninfo
- * bound: true
- * description: Sets the number of pixels between major tick marks.
- *
- */
- public void setMajorTickSpacing(int n) {
- int oldValue = majorTickSpacing;
- majorTickSpacing = n;
- if ( labelTable == null && getMajorTickSpacing() > 0 && getPaintLabels() ) {
- setLabelTable( createStandardLabels( getMajorTickSpacing() ) );
- }
- firePropertyChange("majorTickSpacing", oldValue, majorTickSpacing);
- }
-
-
-
- /**
- * @return the number of pixels between minor ticks
- * @see #getMinorTickSpacing
- */
- public int getMinorTickSpacing() {
- return minorTickSpacing;
- }
-
-
- /**
- * Sets the number of pixels between minor tick marks.
- * @see #getMinorTickSpacing
- * @beaninfo
- * bound: true
- * description: Sets the number of pixels between minor tick marks.
- */
- public void setMinorTickSpacing(int n) {
- int oldValue = minorTickSpacing;
- minorTickSpacing = n;
- firePropertyChange("minorTickSpacing", oldValue, minorTickSpacing);
- }
-
-
- /**
- * Returns true if the knob (and the data value it represents)
- * resolve to the closest tick mark next to where the user
- * positioned the knob.
- *
- * @return true if the value snaps to the nearest tick mark, else false
- * @see #setSnapToTicks
- */
- public boolean getSnapToTicks() {
- return snapToTicks;
- }
-
-
- /**
- * Specifying true makes the knob (and the data value it represents)
- * resolve to the closest tick mark next to where the user
- * positioned the knob.
- *
- * @param b true to snap the knob to the nearest tick mark
- * @see #getSnapToTicks
- * @beaninfo
- * bound: true
- * description: If true snap the knob to the nearest tick mark.
- */
- public void setSnapToTicks(boolean b) {
- boolean oldValue = snapToTicks;
- snapToTicks = b;
- firePropertyChange("snapToTicks", oldValue, snapToTicks);
- }
-
-
- /**
- * @return true if tick marks are painted, else false
- * @see #setPaintTicks
- */
- public boolean getPaintTicks() {
- return paintTicks;
- }
-
-
- /**
- * Determines whether tick marks are painted on the slider.
- * @see #getPaintTicks
- * @beaninfo
- * bound: true
- * description: If true tick marks are painted on the slider.
- */
- public void setPaintTicks(boolean b) {
- boolean oldValue = paintTicks;
- paintTicks = b;
- firePropertyChange("paintTicks", oldValue, paintTicks);
- }
-
-
-
- /**
- * @return true if labels are painted, else false
- * @see #setPaintLabels
- */
- public boolean getPaintLabels() {
- return paintLabels;
- }
-
-
- /**
- * Determines whether labels are painted on the slider.
- * @see #getPaintLabels
- * @beaninfo
- * bound: true
- * description: If true labels are painted on the slider.
- */
- public void setPaintLabels(boolean b) {
- boolean oldValue = paintLabels;
- paintLabels = b;
- if ( labelTable == null && getMajorTickSpacing() > 0 ) {
- setLabelTable( createStandardLabels( getMajorTickSpacing() ) );
- }
- firePropertyChange("paintLabels", oldValue, paintLabels);
- }
-
-
-
- /**
- * Returns a string containing that displays and identifies this
- * object's propeties.
- */
- public String toString() {
- String containerString = "";
-
- if (!isEnabled() && !isVisible()) containerString = "(not Enabled, not Visible)";
- else if (!isEnabled()) containerString = "(not Enabled)";
- else if (!isVisible()) containerString = "(not Visible)";
-
- String sliderString =
- containerString +
- ((getOrientation() ==
- VERTICAL) ? "vertical" : "horizontal" ) + ", " +
- "value=" + getValue() + ", " +
- "adj=" + getValueIsAdjusting() + ", " +
- "min=" + getMinimum() + ", " +
- "max=" + getMaximum() + ", " +
- "majorTickSpacing=" + getMajorTickSpacing() + ", " +
- "minorTickSpacing=" + getMinorTickSpacing() + ", " +
- "snapToTicks=" + getSnapToTicks() + ", " +
- "isInverted=" + getInverted() + ", " +
- "paintLabels=" + getPaintLabels() + ", " +
- "paintTicks=" + getPaintTicks();
-
- return getClass().getName() + "[" + sliderString + "]";
- }
-
-
-
- /////////////////
- // Accessibility support
- ////////////////
-
- /**
- * Get the AccessibleContext associated with this JComponent
- *
- * @return the AccessibleContext of this JComponent
- */
- public AccessibleContext getAccessibleContext() {
- if (accessibleContext == null) {
- accessibleContext = new AccessibleJSlider();
- }
- return accessibleContext;
- }
-
- /**
- * The class used to obtain the accessible role for this object.
- * <p>
- * Warning: serialized objects of this class will not be compatible with
- * future swing releases. The current serialization support is appropriate
- * for short term storage or RMI between Swing1.0 applications. It will
- * not be possible to load serialized Swing1.0 objects with future releases
- * of Swing. The JDK1.2 release of Swing will be the compatibility
- * baseline for the serialized form of Swing objects.
- */
- protected class AccessibleJSlider extends AccessibleJComponent
- implements AccessibleValue {
-
- /**
- * Get the state set of this object.
- *
- * @return an instance of AccessibleState containing the current state
- * of the object
- * @see AccessibleState
- */
- public AccessibleStateSet getAccessibleStateSet() {
- AccessibleStateSet states = super.getAccessibleStateSet();
- if (getValueIsAdjusting()) {
- states.add(AccessibleState.BUSY);
- }
- if (getOrientation() == VERTICAL) {
- states.add(AccessibleState.VERTICAL);
- } else {
- states.add(AccessibleState.HORIZONTAL);
- }
- return states;
- }
-
- /**
- * Get the role of this object.
- *
- * @return an instance of AccessibleRole describing the role of the object
- */
- public AccessibleRole getAccessibleRole() {
- return AccessibleRole.SLIDER;
- }
-
- /**
- * Get the AccessibleValue associated with this object if one
- * exists. Otherwise return null.
- */
- public AccessibleValue getAccessibleValue() {
- return this;
- }
-
- /**
- * Get the accessible value of this object.
- *
- * @return The current value of this object.
- */
- public Number getCurrentAccessibleValue() {
- return new Integer(getValue());
- }
-
- /**
- * Set the value of this object as a Number.
- *
- * @return True if the value was set.
- */
- public boolean setCurrentAccessibleValue(Number n) {
- if (n instanceof Integer) {
- setValue(n.intValue());
- return true;
- } else {
- return false;
- }
- }
-
- /**
- * Get the minimum accessible value of this object.
- *
- * @return The minimum value of this object.
- */
- public Number getMinimumAccessibleValue() {
- return new Integer(getMinimum());
- }
-
- /**
- * Get the maximum accessible value of this object.
- *
- * @return The maximum value of this object.
- */
- public Number getMaximumAccessibleValue() {
- return new Integer(getMaximum());
- }
- } // AccessibleJSlider
- }
-