home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Programming Languages Suite
/
ProgLangD.iso
/
VCAFE.3.0A
/
JFC.bin
/
JSlider.java
< prev
next >
Wrap
Text File
|
1998-06-30
|
28KB
|
917 lines
/*
* @(#)JSlider.java 1.59 98/02/16
*
* 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 com.sun.java.swing;
import com.sun.java.swing.border.*;
import com.sun.java.swing.event.*;
import com.sun.java.swing.plaf.*;
import com.sun.java.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>
* For the keyboard keys used by this component in the standard Look and
* Feel (L&F) renditions, see the
* <a href="doc-files/Key-Index.html#JSlider">JSlider</a> key assignments.
* <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.59 02/16/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
}