/*
* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*/
package javax.swing;
import javax.swing.event.*;
import java.io.
Serializable;
import java.util.
EventListener;
/**
* A generic implementation of BoundedRangeModel.
* <p>
* <strong>Warning:</strong>
* 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 applications running
* the same version of Swing. As of 1.4, support for long term storage
* of all JavaBeans™
* has been added to the <code>java.beans</code> package.
* Please see {@link java.beans.XMLEncoder}.
*
* @author David Kloba
* @author Hans Muller
* @see BoundedRangeModel
*/
public class
DefaultBoundedRangeModel implements
BoundedRangeModel,
Serializable
{
/**
* Only one <code>ChangeEvent</code> is needed per model instance since the
* event's only (read-only) state is the source property. The source
* of events generated here is always "this".
*/
protected transient
ChangeEvent changeEvent = null;
/** The listeners waiting for model changes. */
protected
EventListenerList listenerList = new
EventListenerList();
private int
value = 0;
private int
extent = 0;
private int
min = 0;
private int
max = 100;
private boolean
isAdjusting = false;
/**
* Initializes all of the properties with default values.
* Those values are:
* <ul>
* <li><code>value</code> = 0
* <li><code>extent</code> = 0
* <li><code>minimum</code> = 0
* <li><code>maximum</code> = 100
* <li><code>adjusting</code> = false
* </ul>
*/
public
DefaultBoundedRangeModel() {
}
/**
* Initializes value, extent, minimum and maximum. Adjusting is false.
* Throws an <code>IllegalArgumentException</code> if the following
* constraints aren't satisfied:
* <pre>
* min <= value <= value+extent <= max
* </pre>
*/
public
DefaultBoundedRangeModel(int
value, int
extent, int
min, int
max)
{
if ((
max >=
min) &&
(
value >=
min) &&
((
value +
extent) >=
value) &&
((
value +
extent) <=
max)) {
this.
value =
value;
this.
extent =
extent;
this.
min =
min;
this.
max =
max;
}
else {
throw new
IllegalArgumentException("invalid range properties");
}
}
/**
* Returns the model's current value.
* @return the model's current value
* @see #setValue
* @see BoundedRangeModel#getValue
*/
public int
getValue() {
return
value;
}
/**
* Returns the model's extent.
* @return the model's extent
* @see #setExtent
* @see BoundedRangeModel#getExtent
*/
public int
getExtent() {
return
extent;
}
/**
* Returns the model's minimum.
* @return the model's minimum
* @see #setMinimum
* @see BoundedRangeModel#getMinimum
*/
public int
getMinimum() {
return
min;
}
/**
* Returns the model's maximum.
* @return the model's maximum
* @see #setMaximum
* @see BoundedRangeModel#getMaximum
*/
public int
getMaximum() {
return
max;
}
/**
* Sets the current value of the model. For a slider, that
* determines where the knob appears. Ensures that the new
* value, <I>n</I> falls within the model's constraints:
* <pre>
* minimum <= value <= value+extent <= maximum
* </pre>
*
* @see BoundedRangeModel#setValue
*/
public void
setValue(int
n) {
n =
Math.
min(
n,
Integer.
MAX_VALUE -
extent);
int
newValue =
Math.
max(
n,
min);
if (
newValue +
extent >
max) {
newValue =
max -
extent;
}
setRangeProperties(
newValue,
extent,
min,
max,
isAdjusting);
}
/**
* Sets the extent to <I>n</I> after ensuring that <I>n</I>
* is greater than or equal to zero and falls within the model's
* constraints:
* <pre>
* minimum <= value <= value+extent <= maximum
* </pre>
* @see BoundedRangeModel#setExtent
*/
public void
setExtent(int
n) {
int
newExtent =
Math.
max(0,
n);
if(
value +
newExtent >
max) {
newExtent =
max -
value;
}
setRangeProperties(
value,
newExtent,
min,
max,
isAdjusting);
}
/**
* Sets the minimum to <I>n</I> after ensuring that <I>n</I>
* that the other three properties obey the model's constraints:
* <pre>
* minimum <= value <= value+extent <= maximum
* </pre>
* @see #getMinimum
* @see BoundedRangeModel#setMinimum
*/
public void
setMinimum(int
n) {
int
newMax =
Math.
max(
n,
max);
int
newValue =
Math.
max(
n,
value);
int
newExtent =
Math.
min(
newMax -
newValue,
extent);
setRangeProperties(
newValue,
newExtent,
n,
newMax,
isAdjusting);
}
/**
* Sets the maximum to <I>n</I> after ensuring that <I>n</I>
* that the other three properties obey the model's constraints:
* <pre>
* minimum <= value <= value+extent <= maximum
* </pre>
* @see BoundedRangeModel#setMaximum
*/
public void
setMaximum(int
n) {
int
newMin =
Math.
min(
n,
min);
int
newExtent =
Math.
min(
n -
newMin,
extent);
int
newValue =
Math.
min(
n -
newExtent,
value);
setRangeProperties(
newValue,
newExtent,
newMin,
n,
isAdjusting);
}
/**
* Sets the <code>valueIsAdjusting</code> property.
*
* @see #getValueIsAdjusting
* @see #setValue
* @see BoundedRangeModel#setValueIsAdjusting
*/
public void
setValueIsAdjusting(boolean
b) {
setRangeProperties(
value,
extent,
min,
max,
b);
}
/**
* Returns true if the value is in the process of changing
* as a result of actions being taken by the user.
*
* @return the value of the <code>valueIsAdjusting</code> property
* @see #setValue
* @see BoundedRangeModel#getValueIsAdjusting
*/
public boolean
getValueIsAdjusting() {
return
isAdjusting;
}
/**
* Sets all of the <code>BoundedRangeModel</code> properties after forcing
* the arguments to obey the usual constraints:
* <pre>
* minimum <= value <= value+extent <= maximum
* </pre>
* <p>
* At most, one <code>ChangeEvent</code> is generated.
*
* @see BoundedRangeModel#setRangeProperties
* @see #setValue
* @see #setExtent
* @see #setMinimum
* @see #setMaximum
* @see #setValueIsAdjusting
*/
public void
setRangeProperties(int
newValue, int
newExtent, int
newMin, int
newMax, boolean
adjusting)
{
if (
newMin >
newMax) {
newMin =
newMax;
}
if (
newValue >
newMax) {
newMax =
newValue;
}
if (
newValue <
newMin) {
newMin =
newValue;
}
/* Convert the addends to long so that extent can be
* Integer.MAX_VALUE without rolling over the sum.
* A JCK test covers this, see bug 4097718.
*/
if (((long)
newExtent + (long)
newValue) >
newMax) {
newExtent =
newMax -
newValue;
}
if (
newExtent < 0) {
newExtent = 0;
}
boolean
isChange =
(
newValue !=
value) ||
(
newExtent !=
extent) ||
(
newMin !=
min) ||
(
newMax !=
max) ||
(
adjusting !=
isAdjusting);
if (
isChange) {
value =
newValue;
extent =
newExtent;
min =
newMin;
max =
newMax;
isAdjusting =
adjusting;
fireStateChanged();
}
}
/**
* Adds a <code>ChangeListener</code>. The change listeners are run each
* time any one of the Bounded Range model properties changes.
*
* @param l the ChangeListener to add
* @see #removeChangeListener
* @see BoundedRangeModel#addChangeListener
*/
public void
addChangeListener(
ChangeListener l) {
listenerList.
add(
ChangeListener.class,
l);
}
/**
* Removes a <code>ChangeListener</code>.
*
* @param l the <code>ChangeListener</code> to remove
* @see #addChangeListener
* @see BoundedRangeModel#removeChangeListener
*/
public void
removeChangeListener(
ChangeListener l) {
listenerList.
remove(
ChangeListener.class,
l);
}
/**
* Returns an array of all the change listeners
* registered on this <code>DefaultBoundedRangeModel</code>.
*
* @return all of this model's <code>ChangeListener</code>s
* or an empty
* array if no change listeners are currently registered
*
* @see #addChangeListener
* @see #removeChangeListener
*
* @since 1.4
*/
public
ChangeListener[]
getChangeListeners() {
return
listenerList.
getListeners(
ChangeListener.class);
}
/**
* Runs each <code>ChangeListener</code>'s <code>stateChanged</code> method.
*
* @see #setRangeProperties
* @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 a string that displays all of the
* <code>BoundedRangeModel</code> properties.
*/
public
String toString() {
String modelString =
"value=" +
getValue() + ", " +
"extent=" +
getExtent() + ", " +
"min=" +
getMinimum() + ", " +
"max=" +
getMaximum() + ", " +
"adj=" +
getValueIsAdjusting();
return
getClass().
getName() + "[" +
modelString + "]";
}
/**
* Returns an array of all the objects currently registered as
* <code><em>Foo</em>Listener</code>s
* upon this model.
* <code><em>Foo</em>Listener</code>s
* are registered using the <code>add<em>Foo</em>Listener</code> method.
* <p>
* You can specify the <code>listenerType</code> argument
* with a class literal, such as <code><em>Foo</em>Listener.class</code>.
* For example, you can query a <code>DefaultBoundedRangeModel</code>
* instance <code>m</code>
* for its change listeners
* with the following code:
*
* <pre>ChangeListener[] cls = (ChangeListener[])(m.getListeners(ChangeListener.class));</pre>
*
* If no such listeners exist,
* this method returns an empty array.
*
* @param listenerType the type of listeners requested;
* this parameter should specify an interface
* that descends from <code>java.util.EventListener</code>
* @return an array of all objects registered as
* <code><em>Foo</em>Listener</code>s
* on this model,
* or an empty array if no such
* listeners have been added
* @exception ClassCastException if <code>listenerType</code> doesn't
* specify a class or interface that implements
* <code>java.util.EventListener</code>
*
* @see #getChangeListeners
*
* @since 1.3
*/
public <T extends
EventListener> T[]
getListeners(
Class<T>
listenerType) {
return
listenerList.
getListeners(
listenerType);
}
}