summaryrefslogtreecommitdiff
path: root/libjava/classpath/javax/swing/JSlider.java
diff options
context:
space:
mode:
Diffstat (limited to 'libjava/classpath/javax/swing/JSlider.java')
-rw-r--r--libjava/classpath/javax/swing/JSlider.java1144
1 files changed, 1144 insertions, 0 deletions
diff --git a/libjava/classpath/javax/swing/JSlider.java b/libjava/classpath/javax/swing/JSlider.java
new file mode 100644
index 000000000..a6f51138d
--- /dev/null
+++ b/libjava/classpath/javax/swing/JSlider.java
@@ -0,0 +1,1144 @@
+/* JSlider.java --
+ Copyright (C) 2002, 2004, 2005, 2006, Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package javax.swing;
+
+import gnu.java.lang.CPStringBuilder;
+
+import java.awt.MenuContainer;
+import java.awt.image.ImageObserver;
+import java.beans.PropertyChangeEvent;
+import java.io.Serializable;
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.Hashtable;
+
+import javax.accessibility.Accessible;
+import javax.accessibility.AccessibleContext;
+import javax.accessibility.AccessibleRole;
+import javax.accessibility.AccessibleState;
+import javax.accessibility.AccessibleStateSet;
+import javax.accessibility.AccessibleValue;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+import javax.swing.plaf.SliderUI;
+import javax.swing.plaf.UIResource;
+
+/**
+ * A visual component that allows selection of a value within a
+ * range by adjusting a thumb in a track. The values for the minimum,
+ * maximum, extent and value are stored in a {@link
+ * DefaultBoundedRangeModel}.
+ * <p>
+ * A <code>JSlider</code> component has the following properties:
+ * </p>
+ *
+ * <table>
+ * <tr><th> Property </th><th> Stored in </th><th> Bound? </th></tr>
+ * <tr><td> extent </td><td> model </td><td> no </td></tr>
+ * <tr><td> inverted </td><td> slider </td><td> yes </td></tr>
+ * <tr><td> labelTable </td><td> slider </td><td> yes </td></tr>
+ * <tr><td> majorTickSpacing </td><td> slider </td><td> yes </td></tr>
+ * <tr><td> maximum </td><td> model </td><td> yes </td></tr>
+ * <tr><td> minimum </td><td> model </td><td> yes </td></tr>
+ * <tr><td> minorTickSpacing </td><td> slider </td><td> yes </td></tr>
+ * <tr><td> model </td><td> slider </td><td> yes </td></tr>
+ * <tr><td> orientation </td><td> slider </td><td> yes </td></tr>
+ * <tr><td> paintLabels </td><td> slider </td><td> yes </td></tr>
+ * <tr><td> paintTicks </td><td> slider </td><td> yes </td></tr>
+ * <tr><td> snapToTicks </td><td> slider </td><td> yes </td></tr>
+ * <tr><td> value </td><td> model </td><td> no </td></tr>
+ * <tr><td> valueIsAdjusting </td><td> model </td><td> no </td></tr>
+ * </table>
+ *
+ * <p>
+ * The various behavioural aspects of these properties follows:
+ * </p>
+ *
+ * <ul>
+ * <li>
+ * When a non-bound property stored in the slider changes, the slider fires
+ * a {@link ChangeEvent} to its change listeners.
+ * </li>
+ * <li>
+ * When a bound property stored in the slider changes, the slider fires a
+ * {@link PropertyChangeEvent} to its property change listeners.
+ * </li>
+ * <li>
+ * If any of the model's properties change, it fires a {@link ChangeEvent} to
+ * its listeners, which include the slider.
+ * </li>
+ * <li>
+ * If the slider receives a {@link ChangeEvent} from its model, it will
+ * propagate the event to its own change listeners, with the event's "source"
+ * property set to refer to the slider, rather than the model.
+ * </li>
+ * </ul>
+ */
+public class JSlider extends JComponent implements SwingConstants, Accessible,
+ ImageObserver,
+ MenuContainer, Serializable
+{
+
+ /**
+ * A little testing shows that the reference implementation creates
+ * labels from a class named LabelUIResource.
+ */
+ private class LabelUIResource
+ extends JLabel
+ implements UIResource
+ {
+ LabelUIResource(String text, int align)
+ {
+ super(text, align);
+ setName("Slider.label");
+ }
+ }
+
+ private static final long serialVersionUID = -1441275936141218479L;
+
+ /**
+ * Provides the accessibility features for the <code>JSlider</code>
+ * component.
+ */
+ protected class AccessibleJSlider extends JComponent.AccessibleJComponent
+ implements AccessibleValue
+ {
+ private static final long serialVersionUID = -6301740148041106789L;
+
+ /**
+ * Creates a new <code>AccessibleJSlider</code> instance.
+ */
+ protected AccessibleJSlider()
+ {
+ // Nothing to do here.
+ }
+
+ /**
+ * Returns a set containing the current state of the {@link JSlider}
+ * component.
+ *
+ * @return The accessible state set.
+ */
+ public AccessibleStateSet getAccessibleStateSet()
+ {
+ AccessibleStateSet result = super.getAccessibleStateSet();
+ if (orientation == JSlider.HORIZONTAL)
+ result.add(AccessibleState.HORIZONTAL);
+ else if (orientation == JSlider.VERTICAL)
+ result.add(AccessibleState.VERTICAL);
+ return result;
+ }
+
+ /**
+ * Returns the accessible role for the <code>JSlider</code> component.
+ *
+ * @return {@link AccessibleRole#SLIDER}.
+ */
+ public AccessibleRole getAccessibleRole()
+ {
+ return AccessibleRole.SLIDER;
+ }
+
+ /**
+ * Returns an object that provides access to the current, minimum and
+ * maximum values for the {@link JSlider}. Since this class implements
+ * {@link AccessibleValue}, it returns itself.
+ *
+ * @return The accessible value.
+ */
+ public AccessibleValue getAccessibleValue()
+ {
+ return this;
+ }
+
+ /**
+ * Returns the current value of the {@link JSlider} component, as an
+ * {@link Integer}.
+ *
+ * @return The current value of the {@link JSlider} component.
+ */
+ public Number getCurrentAccessibleValue()
+ {
+ return new Integer(getValue());
+ }
+
+ /**
+ * Sets the current value of the {@link JSlider} component and sends a
+ * {@link PropertyChangeEvent} (with the property name
+ * {@link AccessibleContext#ACCESSIBLE_VALUE_PROPERTY}) to all registered
+ * listeners. If the supplied value is <code>null</code>, this method
+ * does nothing and returns <code>false</code>.
+ *
+ * @param value the new slider value (<code>null</code> permitted).
+ *
+ * @return <code>true</code> if the slider value is updated, and
+ * <code>false</code> otherwise.
+ */
+ public boolean setCurrentAccessibleValue(Number value)
+ {
+ if (value == null)
+ return false;
+ Number oldValue = getCurrentAccessibleValue();
+ setValue(value.intValue());
+ firePropertyChange(AccessibleContext.ACCESSIBLE_VALUE_PROPERTY, oldValue,
+ new Integer(getValue()));
+ return true;
+ }
+
+ /**
+ * Returns the minimum value of the {@link JSlider} component, as an
+ * {@link Integer}.
+ *
+ * @return The minimum value of the {@link JSlider} component.
+ */
+ public Number getMinimumAccessibleValue()
+ {
+ return new Integer(getMinimum());
+ }
+
+ /**
+ * Returns the maximum value of the {@link JSlider} component, as an
+ * {@link Integer}.
+ *
+ * @return The maximum value of the {@link JSlider} component.
+ */
+ public Number getMaximumAccessibleValue()
+ {
+ return new Integer(getMaximum());
+ }
+ }
+
+ /** Whether or not this slider paints its ticks. */
+ private transient boolean paintTicks;
+
+ /** Whether or not this slider paints its track. */
+ private transient boolean paintTrack = true;
+
+ /** Whether or not this slider paints its labels. */
+ private transient boolean paintLabels;
+
+ /**
+ * A dictionary of (Integer, Component) pairs where each Component is a
+ * JLabel and the Integer determines where the label will be painted.
+ */
+ private transient Dictionary labelTable;
+
+ /** The model used to store the slider's range and current value. */
+ protected BoundedRangeModel sliderModel;
+
+ /** The space/distance between major ticks. */
+ protected int majorTickSpacing;
+
+ /** The space/distance between minor ticks. */
+ protected int minorTickSpacing;
+
+ /** Whether the slider snaps its values to ticks. */
+ protected boolean snapToTicks;
+
+ /** The orientation (horizontal or vertical) of the slider. */
+ protected int orientation = HORIZONTAL;
+
+ /** Whether the slider is inverted. */
+ private transient boolean isInverted;
+
+ /**
+ * The listener that monitors the slider's model and forwards events to the
+ * slider's listeners (see <code>createChangeListener()</code>).
+ */
+ protected ChangeListener changeListener;
+
+ /** The change event that is passed to all listeners of this slider. */
+ protected transient ChangeEvent changeEvent;
+
+ /**
+ * Creates a new horizontal <code>JSlider</code> instance with a minimum of
+ * 0, a maximum of 100, and a value of 50.
+ */
+ public JSlider()
+ {
+ this(HORIZONTAL, 0, 100, 50);
+ }
+
+ /**
+ * Creates a new <code>JSlider</code> instance with the given orientation
+ * and a minimum of 0, a maximum of 100, and a value of 50.
+ *
+ * @param orientation The orientation of the slider ({@link #HORIZONTAL} or
+ * {@link #VERTICAL}).
+ *
+ * @throws IllegalArgumentException if <code>orientation</code> is not one of
+ * the specified values.
+ */
+ public JSlider(int orientation)
+ {
+ this(orientation, 0, 100, 50);
+ }
+
+ /**
+ * Creates a new horizontal <code>JSlider</code> instance with the given
+ * maximum and minimum and a value that is halfway between the minimum and the
+ * maximum.
+ *
+ * @param minimum The minimum value.
+ * @param maximum The maximum value.
+ *
+ * @throws IllegalArgumentException if <code>minimum</code> is greater than
+ * <code>maximum</code>.
+ */
+ public JSlider(int minimum, int maximum)
+ {
+ this(HORIZONTAL, minimum, maximum, (maximum + minimum) / 2);
+ }
+
+ /**
+ * Creates a new horizontal <code>JSlider</code> instance with the given
+ * minimum, maximum, and value.
+ *
+ * @param minimum The minimum value.
+ * @param maximum The maximum value.
+ * @param value The initial value.
+ *
+ * @throws IllegalArgumentException if <code>value</code> is not in the
+ * specified range.
+ * @throws IllegalArgumentException if <code>minimum</code> is greater than
+ * <code>maximum</code>.
+ */
+ public JSlider(int minimum, int maximum, int value)
+ {
+ this(HORIZONTAL, minimum, maximum, value);
+ }
+
+ /**
+ * Creates a new <code>JSlider</code> instance with the given orientation,
+ * minimum, maximum, and value.
+ *
+ * @param orientation The orientation of the slider ({@link #HORIZONTAL} or
+ * {@link #VERTICAL}).
+ * @param minimum The minimum value of the JSlider.
+ * @param maximum The maximum value of the JSlider.
+ * @param value The initial value of the JSlider.
+ *
+ * @throws IllegalArgumentException if <code>orientation</code> is not one of
+ * the specified values.
+ * @throws IllegalArgumentException if <code>value</code> is not in the
+ * specified range.
+ * @throws IllegalArgumentException if <code>minimum</code> is greater than
+ * <code>maximum</code>.
+ */
+ public JSlider(int orientation, int minimum, int maximum, int value)
+ {
+ sliderModel = new DefaultBoundedRangeModel(value, 0, minimum, maximum);
+ if (orientation != HORIZONTAL && orientation != VERTICAL)
+ throw new IllegalArgumentException(orientation
+ + " is not a legal orientation");
+ this.orientation = orientation;
+ changeListener = createChangeListener();
+ sliderModel.addChangeListener(changeListener);
+ updateUI();
+ }
+
+ /**
+ * Creates a new horizontal <code>JSlider</code> instance with the given
+ * model.
+ *
+ * @param model The model (<code>null</code> not permitted).
+ *
+ * @throws NullPointerException if <code>model</code> is <code>null</code>.
+ */
+ public JSlider(BoundedRangeModel model)
+ {
+ sliderModel = model;
+ changeListener = createChangeListener();
+ sliderModel.addChangeListener(changeListener);
+ updateUI();
+ }
+
+ /**
+ * Returns the slider's value (from the slider's model).
+ *
+ * @return The value of the slider.
+ *
+ * @see #setValue(int)
+ */
+ public int getValue()
+ {
+ return sliderModel.getValue();
+ }
+
+ /**
+ * Sets the slider's value and sends a {@link ChangeEvent} to all
+ * registered listeners. Note that the model will fire a change event to all
+ * of its registered listeners first (with the model as the event source) and
+ * then the slider will fire another change event to all of its registered
+ * listeners (this time with the slider as the event source).
+ *
+ * @param value the new value.
+ *
+ * @see #getValue()
+ */
+ public void setValue(int value)
+ {
+ sliderModel.setValue(value);
+ }
+
+ /**
+ * Returns the slider's UI delegate.
+ *
+ * @return The slider's UI delegate.
+ */
+ public SliderUI getUI()
+ {
+ return (SliderUI) ui;
+ }
+
+ /**
+ * Sets the slider's UI delegate.
+ *
+ * @param ui the UI delegate.
+ */
+ public void setUI(SliderUI ui)
+ {
+ super.setUI(ui);
+ }
+
+ /**
+ * Sets this slider's UI delegate to the default (obtained from the
+ * {@link UIManager}) for the current look and feel.
+ */
+ public void updateUI()
+ {
+ updateLabelUIs();
+ setUI((SliderUI) UIManager.getUI(this));
+ }
+
+ /**
+ * Returns the suffix (<code>"SliderUI"</code> in this case) used to
+ * determine the class name for a UI delegate that can provide the look and
+ * feel for a <code>JSlider</code>.
+ *
+ * @return <code>"SliderUI"</code>.
+ */
+ public String getUIClassID()
+ {
+ return "SliderUI";
+ }
+
+ /**
+ * Creates a {@link ChangeListener} that is added to the slider's model and
+ * forwards change events generated by the model to the listeners that are
+ * registered with the <code>JSlider</code> (by calling the
+ * {@link #fireStateChanged} method).
+ *
+ * @return A new listener.
+ */
+ protected ChangeListener createChangeListener()
+ {
+ return new ChangeListener()
+ {
+ public void stateChanged(ChangeEvent ce)
+ {
+ // No need to trigger a repaint since the UI listens to the model
+ // as well. All we need to do is pass on the stateChanged event
+ // to our listeners.
+ fireStateChanged();
+ }
+ };
+ }
+
+ /**
+ * Registers a listener with the slider so that it will receive
+ * {@link ChangeEvent} notifications. Note that change events generated
+ * by the slider's model will be forwarded automatically to the slider's
+ * listeners.
+ *
+ * @param listener the listener to register.
+ *
+ * @see #removeChangeListener(ChangeListener)
+ */
+ public void addChangeListener(ChangeListener listener)
+ {
+ listenerList.add(ChangeListener.class, listener);
+ }
+
+ /**
+ * Removes a listener from this slider so that it will no longer receive
+ * {@link ChangeEvent} notifications from the slider.
+ *
+ * @param listener The listener to remove.
+ *
+ * @see #addChangeListener(ChangeListener)
+ */
+ public void removeChangeListener(ChangeListener listener)
+ {
+ listenerList.remove(ChangeListener.class, listener);
+ }
+
+ /**
+ * Sends a {@link ChangeEvent} to all registered listeners, with this slider
+ * as the source.
+ */
+ protected void fireStateChanged()
+ {
+ Object[] changeListeners = listenerList.getListenerList();
+ if (changeEvent == null)
+ changeEvent = new ChangeEvent(this);
+ for (int i = changeListeners.length - 2; i >= 0; i -= 2)
+ {
+ if (changeListeners[i] == ChangeListener.class)
+ ((ChangeListener) changeListeners[i + 1]).stateChanged(changeEvent);
+ }
+ }
+
+ /**
+ * Returns an array containing all the {@link ChangeListener} instances
+ * registered with this slider. If no listeners are registered, this method
+ * returns an empty array.
+ *
+ * @return An array array containing all the {@link ChangeListener} instances
+ * registered with this slider (possibly empty, but never
+ * <code>null</code>).
+ */
+ public ChangeListener[] getChangeListeners()
+ {
+ return (ChangeListener[]) listenerList.getListeners(ChangeListener.class);
+ }
+
+ /**
+ * Returns the slider's model, which stores the minimum, maximum and current
+ * values.
+ *
+ * @return The slider's model.
+ *
+ * @see #setModel(BoundedRangeModel)
+ */
+ public BoundedRangeModel getModel()
+ {
+ return sliderModel;
+ }
+
+ /**
+ * Sets the slider's model and sends a {@link PropertyChangeEvent} (with the
+ * property name "model") to all registered listeners. The change listener
+ * that the slider registered with the original model is removed and added
+ * to the new model (this ensures that {@link ChangeEvent} notifications
+ * generated by the model are automatically forwarded to listeners that are
+ * registered with the slider).
+ *
+ * @param model The model to use with the slider.
+ *
+ * @see #getModel()
+ */
+ public void setModel(BoundedRangeModel model)
+ {
+ // I didn't do the null pointer check on purpose.
+ // If you try it with Sun's, it'll go ahead and set it to null
+ // and bork the next time it tries to access the model.
+ if (model != sliderModel)
+ {
+ BoundedRangeModel oldModel = sliderModel;
+ sliderModel = model;
+ oldModel.removeChangeListener(changeListener);
+ sliderModel.addChangeListener(changeListener);
+ firePropertyChange("model", oldModel, sliderModel);
+ }
+ }
+
+ /**
+ * Returns the minimum value of the slider (from the slider's model).
+ *
+ * @return The minimum value of the slider.
+ *
+ * @see #setMinimum(int)
+ */
+ public int getMinimum()
+ {
+ return sliderModel.getMinimum();
+ }
+
+ /**
+ * Sets the minimum value of the slider and fires a
+ * {@link PropertyChangeEvent} (with the property name "minimum") to all
+ * registered listeners. Note that:
+ * <p>
+ * <ul>
+ * <li>the minimum value is stored in the slider's model (see
+ * {@link #getModel()});</li>
+ * <li>in addition to the property change event, the slider also fires a
+ * {@link ChangeEvent}.</li>
+ * </ul>
+ *
+ * @param minimum The minimum value of the slider.
+ *
+ * @see #getMinimum()
+ */
+ public void setMinimum(int minimum)
+ {
+ int old = sliderModel.getMinimum();
+ sliderModel.setMinimum(minimum);
+ if (minimum != old)
+ firePropertyChange("minimum", old, minimum);
+ }
+
+ /**
+ * Returns the slider's maximum value (obtained from the slider's model).
+ *
+ * @return The maximum value of the slider.
+ *
+ * @see #setMaximum(int)
+ */
+ public int getMaximum()
+ {
+ return sliderModel.getMaximum();
+ }
+
+ /**
+ * Sets the maximum value of the slider and fires a
+ * {@link PropertyChangeEvent} (with the property name "maximum") to all
+ * registered listeners. Note that:
+ * <p>
+ * <ul>
+ * <li>the maximum value is stored in the slider's model (see
+ * {@link #getModel()});</li>
+ * <li>in addition to the property change event, the slider also fires a
+ * {@link ChangeEvent}.</li>
+ * </ul>
+ *
+ * @param maximum The maximum value of the slider.
+ *
+ * @see #getMaximum()
+ */
+ public void setMaximum(int maximum)
+ {
+ int old = sliderModel.getMaximum();
+ sliderModel.setMaximum(maximum);
+ if (maximum != old)
+ firePropertyChange("maximum", old, maximum);
+ }
+
+ /**
+ * Returns the <code>valueIsAdjusting</code> flag from the slider's model.
+ *
+ * @return The <code>valueIsAdjusting</code> flag from the slider's model.
+ *
+ * @see #setValueIsAdjusting(boolean)
+ */
+ public boolean getValueIsAdjusting()
+ {
+ return sliderModel.getValueIsAdjusting();
+ }
+
+ /**
+ * Sets the <code>valueIsAdjusting</code> flag in the slider's model, and
+ * sends a {@link ChangeEvent} to all registered listeners.
+ *
+ * @param adjusting the new flag value.
+ *
+ * @see #getValueIsAdjusting()
+ */
+ public void setValueIsAdjusting(boolean adjusting)
+ {
+ sliderModel.setValueIsAdjusting(adjusting);
+ }
+
+ /**
+ * Returns the slider's extent value, obtained from the slider's model.
+ *
+ * @return The extent value.
+ *
+ * @see #setExtent(int)
+ */
+ public int getExtent()
+ {
+ return sliderModel.getExtent();
+ }
+
+ /**
+ * Sets the slider's extent value and sends a {@link ChangeEvent} to all
+ * registered listeners. Note that the model will fire a change event to all
+ * of its registered listeners first (with the model as the event source) and
+ * then the slider will fire another change event to all of its registered
+ * listeners (this time with the slider as the event source).
+ *
+ * @param extent The extent value for this slider.
+ *
+ * @see #getExtent()
+ */
+ public void setExtent(int extent)
+ {
+ sliderModel.setExtent(extent);
+ }
+
+ /**
+ * Returns the orientation of the slider, either {@link JSlider#HORIZONTAL}
+ * or {@link JSlider#VERTICAL}.
+ *
+ * @return The orientation of the slider.
+ *
+ * @see #setOrientation(int)
+ */
+ public int getOrientation()
+ {
+ return orientation;
+ }
+
+ /**
+ * Sets the orientation for the slider and sends a
+ * {@link PropertyChangeEvent} (with the property name "orientation") to all
+ * registered listeners.
+ *
+ * @param orientation the orientation (one of {@link JSlider#HORIZONTAL} or
+ * {@link JSlider#VERTICAL}).
+ *
+ * @throws IllegalArgumentException if <code>orientation</code> is not one of
+ * the permitted values.
+ *
+ * @see #getOrientation()
+ */
+ public void setOrientation(int orientation)
+ {
+ if (orientation != VERTICAL && orientation != HORIZONTAL)
+ throw new IllegalArgumentException(
+ "orientation must be one of: VERTICAL, HORIZONTAL");
+ if (orientation != this.orientation)
+ {
+ int oldOrientation = this.orientation;
+ this.orientation = orientation;
+ firePropertyChange("orientation", oldOrientation, this.orientation);
+ revalidate();
+ }
+ }
+
+ /**
+ * Returns the label table for the slider.
+ *
+ * @return The label table for the slider (possibly <code>null</code>).
+ *
+ * @see #setLabelTable(Dictionary)
+ */
+ public Dictionary getLabelTable()
+ {
+ return labelTable;
+ }
+
+ /**
+ * Sets the table of labels for the slider and sends a
+ * {@link PropertyChangeEvent} (with the property name "labelTable") to all
+ * registered listeners.
+ *
+ * @param table the table of labels (<code>null</code> permitted).
+ *
+ * @see #getLabelTable()
+ */
+ public void setLabelTable(Dictionary table)
+ {
+ if (table != labelTable)
+ {
+ Dictionary oldTable = labelTable;
+ labelTable = table;
+ updateLabelUIs();
+ firePropertyChange("labelTable", oldTable, labelTable);
+ revalidate();
+ repaint();
+ }
+ }
+
+ /**
+ * Resets the UI delegates for the labels in the <code>labelTable</code> to
+ * the default for the current look and feel.
+ */
+ protected void updateLabelUIs()
+ {
+ if (labelTable != null)
+ {
+ for (Enumeration list = labelTable.elements(); list.hasMoreElements();)
+ {
+ Object o = list.nextElement();
+ if (o instanceof JComponent)
+ {
+ JComponent jc = (JComponent) o;
+ jc.updateUI();
+ jc.setSize(jc.getPreferredSize());
+ }
+ }
+ }
+ }
+
+ /**
+ * Creates a hashtable of <code>(Integer, JLabel)</code> pairs that can be
+ * used as a label table for this slider. The labels will start from the
+ * slider's minimum and increase by the increment. Each label will have a text
+ * string indicating its integer value.
+ *
+ * @param increment The increment between labels (must be > 0).
+ *
+ * @return A hashtable containing the labels.
+ *
+ * @throws IllegalArgumentException if <code>increment</code> is not greater
+ * than zero.
+ */
+ public Hashtable createStandardLabels(int increment)
+ {
+ return createStandardLabels(increment, sliderModel.getMinimum());
+ }
+
+ /**
+ * Creates a hashtable of <code>(Integer, JLabel)</code> pairs that can be
+ * used as a label table for this slider. The labels will start from the
+ * given start value and increase by the increment. Each label will have a
+ * text string indicating its integer value.
+ *
+ * @param increment The increment between labels (must be > 0).
+ * @param start The value to start from.
+ *
+ * @return A hashtable with the labels and their keys.
+ *
+ * @throws IllegalArgumentException if <code>increment</code> is not greater
+ * than zero, or <code>start</code> is not within the range of the
+ * model.
+ */
+ public Hashtable createStandardLabels(int increment, int start)
+ {
+ if (increment <= 0)
+ throw new IllegalArgumentException("Requires 'increment' > 0.");
+ if (start < getMinimum() || start > getMaximum())
+ throw new IllegalArgumentException("The 'start' value is out of range.");
+ Hashtable table = new Hashtable();
+ int max = getMaximum();
+ for (int i = start; i <= max; i += increment)
+ {
+ LabelUIResource label = new LabelUIResource(String.valueOf(i),
+ JLabel.CENTER);
+ table.put(new Integer(i), label);
+ }
+ return table;
+ }
+
+ /**
+ * Returns the flag that controls whether or not the value scale for the
+ * slider is inverted (the default value is <code>false</code>).
+ *
+ * @return The flag that controls whether or not the value scale for the
+ * slider is inverted.
+ *
+ * @see #setInverted(boolean)
+ */
+ public boolean getInverted()
+ {
+ return isInverted;
+ }
+
+ /**
+ * Sets the flag that controls whether or not the value scale for the
+ * slider is inverted and, if the new flag value is different to the old flag
+ * value, sends a {@link PropertyChangeEvent} to all registered listeners.
+ * Typically, a horizontal slider will display a scale that increases from
+ * left to right, but this is reversed if the 'inverted' flag is set to
+ * <code>true</code>. Similarly, a vertical slider will display a scale that
+ * increases from bottom to top, and this is reversed if the 'inverted' flag
+ * is set to <code>true</code>.
+ *
+ * @param inverted the new flag value.
+ *
+ * @see #getInverted()
+ */
+ public void setInverted(boolean inverted)
+ {
+ if (isInverted != inverted)
+ {
+ boolean oldInverted = isInverted;
+ isInverted = inverted;
+ firePropertyChange("inverted", oldInverted, isInverted);
+ repaint();
+ }
+ }
+
+ /**
+ * Returns the distance between major tick marks along the slider's value
+ * scale.
+ *
+ * @return The amount of units between each major tick mark.
+ *
+ * @see #setMajorTickSpacing(int)
+ */
+ public int getMajorTickSpacing()
+ {
+ return majorTickSpacing;
+ }
+
+ /**
+ * Sets the distance between major tick marks along the slider's value scale,
+ * and sends a {@link PropertyChangeEvent} (with the property name
+ * "majorTickSpacing") to all registered listeners.
+ *
+ * @param spacing the distance between major tick marks.
+ *
+ * @see #getMajorTickSpacing()
+ */
+ public void setMajorTickSpacing(int spacing)
+ {
+ if (majorTickSpacing != spacing)
+ {
+ int oldSpacing = majorTickSpacing;
+ majorTickSpacing = spacing;
+ if (labelTable == null && majorTickSpacing > 0 && getPaintLabels())
+ setLabelTable(createStandardLabels(majorTickSpacing));
+ firePropertyChange("majorTickSpacing", oldSpacing, majorTickSpacing);
+ if (getPaintTicks())
+ repaint();
+ }
+ }
+
+ /**
+ * Returns the distance between minor tick marks along the slider's value
+ * scale.
+ *
+ * @return The distance between minor tick marks along the slider's value
+ * scale.
+ *
+ * @see #setMinorTickSpacing(int)
+ */
+ public int getMinorTickSpacing()
+ {
+ return minorTickSpacing;
+ }
+
+ /**
+ * Sets the distance between minor tick marks along the slider's value scale,
+ * and sends a {@link PropertyChangeEvent} (with the property name
+ * "minorTickSpacing") to all registered listeners.
+ *
+ * @param spacing the distance between minor tick marks.
+ *
+ * @see #getMinorTickSpacing()
+ */
+ public void setMinorTickSpacing(int spacing)
+ {
+ if (minorTickSpacing != spacing)
+ {
+ int oldSpacing = minorTickSpacing;
+ minorTickSpacing = spacing;
+ firePropertyChange("minorTickSpacing", oldSpacing, minorTickSpacing);
+ if (getPaintTicks())
+ repaint();
+ }
+ }
+
+ /**
+ * Returns the flag that controls whether the slider thumb will snap to ticks.
+ * Sliders that snap to ticks will automatically move the thumb to the
+ * nearest tick mark.
+ *
+ * @return <code>true</code> if the slider thumb automatically.
+ *
+ * @see #setSnapToTicks(boolean)
+ */
+ public boolean getSnapToTicks()
+ {
+ return snapToTicks;
+ }
+
+ /**
+ * Sets the flag that controls whether the slider thumb will snap to ticks
+ * and sends a {@link PropertyChangeEvent} (with the property name
+ * 'snapToTicks') to all registered listeners. Sliders that snap to ticks
+ * will automatically move the thumb to the nearest tick mark.
+ *
+ * @param snap the new flag value.
+ *
+ * @see #getSnapToTicks()
+ */
+ public void setSnapToTicks(boolean snap)
+ {
+ if (snap != snapToTicks)
+ {
+ snapToTicks = snap;
+ firePropertyChange("snapToTicks", !snap, snap);
+ }
+ }
+
+ /**
+ * Returns the flag that controls whether or not tick marks are painted along
+ * the slider's value scale.
+ *
+ * @return <code>true</code> if tick marks should be painted, and
+ * <code>false</code> if tick marks should not be painted.
+ *
+ * @see #setPaintTicks(boolean)
+ */
+ public boolean getPaintTicks()
+ {
+ return paintTicks;
+ }
+
+ /**
+ * Sets the flag that controls whether or not tick marks are painted along
+ * the slider's value scale, and sends a {@link PropertyChangeEvent} (with
+ * the property name "paintTicks") to all registered listeners. In
+ * addition to setting this property to <code>true</code>, one or both of the
+ * minor tick spacing and major tick spacing attributes must be set to a
+ * value greater than 0 in order for ticks to be painted.
+ *
+ * @param paint Whether ticks will be painted.
+ *
+ * @see #getPaintTicks()
+ */
+ public void setPaintTicks(boolean paint)
+ {
+ if (paint != paintTicks)
+ {
+ boolean oldPaintTicks = paintTicks;
+ paintTicks = paint;
+ firePropertyChange("paintTicks", oldPaintTicks, paintTicks);
+ revalidate();
+ repaint();
+ }
+ }
+
+ /**
+ * Returns the flag that controls whether or not the track is painted.
+ *
+ * @return Whether the track will be painted.
+ *
+ * @see #setPaintTrack(boolean)
+ */
+ public boolean getPaintTrack()
+ {
+ return paintTrack;
+ }
+
+ /**
+ * Sets the flag that controls whether or not the track is painted, and
+ * sends a {@link PropertyChangeEvent} (for the "paintTrack" property) to all
+ * registered listeners.
+ *
+ * @param paint Whether the track will be painted.
+ *
+ * @see #getPaintTrack()
+ */
+ public void setPaintTrack(boolean paint)
+ {
+ if (paintTrack != paint)
+ {
+ paintTrack = paint;
+ firePropertyChange("paintTrack", !paint, paint);
+ repaint();
+ }
+ }
+
+ /**
+ * Returns the flag that controls whether or not labels are painted for the
+ * tick marks along the slider.
+ *
+ * @return Whether labels will be painted.
+ *
+ * @see #setPaintLabels(boolean)
+ */
+ public boolean getPaintLabels()
+ {
+ return paintLabels;
+ }
+
+ /**
+ * Sets the flag that controls whether or not labels are painted for the
+ * tick marks along the slider and sends a {@link PropertyChangeEvent} (with
+ * the property name "paintLabels") to all registered listeners.
+ *
+ * @param paint Whether labels will be painted.
+ *
+ * @see #getPaintLabels()
+ */
+ public void setPaintLabels(boolean paint)
+ {
+ if (paint != paintLabels)
+ {
+ paintLabels = paint;
+ if (paint && majorTickSpacing > 0 && labelTable == null)
+ setLabelTable(createStandardLabels(majorTickSpacing));
+ firePropertyChange("paintLabels", !paint, paint);
+ revalidate();
+ repaint();
+ }
+ }
+
+ /**
+ * Returns an implementation-dependent string describing the attributes of
+ * this <code>JSlider</code>.
+ *
+ * @return A string describing the attributes of this <code>JSlider</code>
+ * (never <code>null</code>).
+ */
+ protected String paramString()
+ {
+ String superParamStr = super.paramString();
+ CPStringBuilder sb = new CPStringBuilder();
+ sb.append(",isInverted=").append(getInverted());
+ sb.append(",majorTickSpacing=").append(getMajorTickSpacing());
+ sb.append(",minorTickSpacing=").append(getMinorTickSpacing());
+ sb.append(",orientation=");
+ if (orientation == HORIZONTAL)
+ sb.append("HORIZONTAL");
+ else
+ sb.append("VERTICAL");
+ sb.append(",paintLabels=").append(getPaintLabels());
+ sb.append(",paintTicks=").append(getPaintTicks());
+ sb.append(",paintTrack=").append(getPaintTrack());
+ sb.append(",snapToTicks=").append(getSnapToTicks());
+
+ // the following is output by the reference implementation. We don't
+ // strictly need to replicate this. Perhaps it has some meaning, but
+ // I couldn't determine it yet...
+ sb.append(",snapToValue=true");
+
+ return superParamStr + sb.toString();
+ }
+
+ /**
+ * Returns the object that provides accessibility features for this
+ * <code>JSlider</code> component.
+ *
+ * @return The accessible context (an instance of {@link AccessibleJSlider}).
+ */
+ public AccessibleContext getAccessibleContext()
+ {
+ if (accessibleContext == null)
+ accessibleContext = new AccessibleJSlider();
+
+ return accessibleContext;
+ }
+}