This is the mail archive of the java-patches@gcc.gnu.org mailing list for the Java project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[gui][PATCH] JSlider


Hi,

This patch implements JSlider and its UI. It also fixes a bug in
layoutCompoundLabel and implements paintComponent.

Cheers,

Kim

2004-11-13  Kim Ho  <kho@redhat.com>

	* Makefile.am: Updated for new file.
	* Makefile.in: Regenerated.
	* javax/swing/JSlider.java: Reimplement.
	* javax/swing/SwingUtilities.java
	(layoutCompoundLabel): Use icon height
	instead of width.
	(paintComponent): Implement.
	* javax/swing/plaf/basic/BasicLookAndFeel.java:
	Add JSlider defaults.
	* javax/swing/plaf/basic/BasicSliderUI.java:
	Implement. New file.


Index: Makefile.am
===================================================================
RCS file: /cvs/gcc/gcc/libjava/Makefile.am,v
retrieving revision 1.361
diff -u -r1.361 Makefile.am
--- Makefile.am	12 Feb 2004 07:10:06 -0000	1.361
+++ Makefile.am	13 Feb 2004 15:22:27 -0000
@@ -1298,6 +1298,7 @@
 javax/swing/plaf/basic/BasicRootPaneUI.java \
 javax/swing/plaf/basic/BasicRadioButtonUI.java \
 javax/swing/plaf/basic/BasicScrollPaneUI.java \
+javax/swing/plaf/basic/BasicSliderUI.java \
 javax/swing/plaf/basic/BasicSplitPaneDivider.java \
 javax/swing/plaf/basic/BasicSplitPaneUI.java \
 javax/swing/plaf/basic/BasicTabbedPaneUI.java \
Index: javax/swing/JSlider.java
===================================================================
RCS file: /cvs/gcc/gcc/libjava/javax/swing/JSlider.java,v
retrieving revision 1.3
diff -u -r1.3 JSlider.java
--- javax/swing/JSlider.java	11 Jun 2003 13:20:39 -0000	1.3
+++ javax/swing/JSlider.java	13 Feb 2004 15:22:29 -0000
@@ -1,5 +1,5 @@
 /* JSlider.java --
-   Copyright (C) 2002 Free Software Foundation, Inc.
+   Copyright (C) 2002, 2004 Free Software Foundation, Inc.
 
 This file is part of GNU Classpath.
 
@@ -35,13 +35,16 @@
 obligated to do so.  If you do not wish to do so, delete this
 exception statement from your version. */
 
-
 package javax.swing;
 
+import java.awt.ComponentOrientation;
+import java.awt.MenuContainer;
+import java.awt.image.ImageObserver;
 import java.io.IOException;
 import java.io.ObjectOutputStream;
 import java.io.Serializable;
 import java.util.Dictionary;
+import java.util.Enumeration;
 import java.util.Hashtable;
 import javax.accessibility.Accessible;
 import javax.accessibility.AccessibleContext;
@@ -50,652 +53,879 @@
 import javax.accessibility.AccessibleValue;
 import javax.swing.event.ChangeEvent;
 import javax.swing.event.ChangeListener;
+import javax.swing.event.EventListenerList;
 import javax.swing.plaf.SliderUI;
 
+
 /**
- * JSlider
- * @author	Andrew Selkirk
- * @version	1.0
+ * <p>
+ * The JSlider is a Swing 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>
+ * 
+ * <p>
+ * JSliders have the following properties:
+ * </p>
+ * 
+ * <table>
+ * <tr><th> Property         </td><th> Stored in </td><th> Bound? </td></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> no     </td></tr>
+ * <tr><td> minimum          </td><td> model     </td><td> no     </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> no     </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 behavioral aspects of these properties follows:
+ * </p>
+ * 
+ * <ul>
+ * <li>
+ * When non-bound properties stored in the slider change, the slider fires
+ * ChangeEvents to its ChangeListeners.
+ * </li>
+ * <li>
+ * When bound properties stored in the slider change, the slider fires
+ * PropertyChangeEvents to its PropertyChangeListeners
+ * </li>
+ * <li>
+ * If any of the model's properties change, it fires a ChangeEvent to its
+ * ChangeListeners, which include the slider.
+ * </li>
+ * <li>
+ * If the slider receives a ChangeEvent from its model, it will propagate the
+ * ChangeEvent to its ChangeListeners, with the ChangeEvent's "source"
+ * property set to refer to the slider, rather than the model.
+ * </li>
+ * </ul>
  */
-public class JSlider
-  extends JComponent
-  implements SwingConstants, Accessible
+public class JSlider extends JComponent implements SwingConstants, Accessible,
+                                                   ImageObserver,
+                                                   MenuContainer, Serializable
 {
   static final long serialVersionUID = -1441275936141218479L;
 
-	//-------------------------------------------------------------
-	// Classes ----------------------------------------------------
-	//-------------------------------------------------------------
-
-
-	/**
-	 * AccessibleJSlider
-	 */
-	protected class AccessibleJSlider extends JComponent.AccessibleJComponent implements AccessibleValue {
-
-		//-------------------------------------------------------------
-		// Variables --------------------------------------------------
-		//-------------------------------------------------------------
-
-
-		//-------------------------------------------------------------
-		// Initialization ---------------------------------------------
-		//-------------------------------------------------------------
-
-		/**
-		 * Constructor AccessibleJSlider
-		 * @param value0 TODO
-		 */
-		protected AccessibleJSlider(JSlider value0) {
-			super(value0);
-			// TODO
-		} // AccessibleJSlider()
-
-
-		//-------------------------------------------------------------
-		// Methods ----------------------------------------------------
-		//-------------------------------------------------------------
-
-		/**
-		 * getAccessibleStateSet
-		 * @returns AccessibleStateSet
-		 */
-		public AccessibleStateSet getAccessibleStateSet() {
-			return null; // TODO
-		} // getAccessibleStateSet()
-
-		/**
-		 * getAccessibleRole
-		 * @returns AccessibleRole
-		 */
-		public AccessibleRole getAccessibleRole() {
-			return null; // TODO
-		} // getAccessibleRole()
-
-		/**
-		 * getAccessibleValue
-		 * @returns AccessibleValue
-		 */
-		public AccessibleValue getAccessibleValue() {
-			return null; // TODO
-		} // getAccessibleValue()
-
-		/**
-		 * getCurrentAccessibleValue
-		 * @returns Number
-		 */
-		public Number getCurrentAccessibleValue() {
-			return null; // TODO
-		} // getCurrentAccessibleValue()
-
-		/**
-		 * setCurrentAccessibleValue
-		 * @param value0 TODO
-		 * @returns boolean
-		 */
-		public boolean setCurrentAccessibleValue(Number value0) {
-			return false; // TODO
-		} // setCurrentAccessibleValue()
-
-		/**
-		 * getMinimumAccessibleValue
-		 * @returns Number
-		 */
-		public Number getMinimumAccessibleValue() {
-			return null; // TODO
-		} // getMinimumAccessibleValue()
-
-		/**
-		 * getMaximumAccessibleValue
-		 * @returns Number
-		 */
-		public Number getMaximumAccessibleValue() {
-			return null; // TODO
-		} // getMaximumAccessibleValue()
-
-
-	} // AccessibleJSlider
-
-	/**
-	 * ModelListener
-	 */
-	private class ModelListener implements ChangeListener, Serializable {
-
-		//-------------------------------------------------------------
-		// Variables --------------------------------------------------
-		//-------------------------------------------------------------
-
-
-		//-------------------------------------------------------------
-		// Initialization ---------------------------------------------
-		//-------------------------------------------------------------
-
-		/**
-		 * Constructor ModelListener
-		 * @param value0 TODO
-		 */
-		private ModelListener(JSlider value0) {
-			// TODO
-		} // ModelListener()
-
-
-		//-------------------------------------------------------------
-		// Methods ----------------------------------------------------
-		//-------------------------------------------------------------
-
-		/**
-		 * stateChanged
-		 * @param value0 TODO
-		 */
-		public void stateChanged(ChangeEvent value0) {
-			// TODO
-		} // stateChanged()
-
-
-	} // ModelListener
-
-
-	//-------------------------------------------------------------
-	// Variables --------------------------------------------------
-	//-------------------------------------------------------------
-
-	/**
-	 * uiClassID
-	 */
-	private static final String uiClassID = "SliderUI";
-
-	/**
-	 * paintTicks
-	 */
-	private boolean paintTicks;
-
-	/**
-	 * paintTrack
-	 */
-	private boolean paintTrack;
-
-	/**
-	 * paintLabels
-	 */
-	private boolean paintLabels;
-
-	/**
-	 * isInverted
-	 */
-	private boolean isInverted;
-
-	/**
-	 * sliderModel
-	 */
-	protected BoundedRangeModel sliderModel;
-
-	/**
-	 * majorTickSpacing
-	 */
-	protected int majorTickSpacing;
-
-	/**
-	 * minorTickSpacing
-	 */
-	protected int minorTickSpacing;
-
-	/**
-	 * snapToTicks
-	 */
-	protected boolean snapToTicks;
-
-	/**
-	 * snapToValue
-	 */
-	boolean snapToValue;
-
-	/**
-	 * orientation
-	 */
-	protected int orientation;
-
-	/**
-	 * labelTable
-	 */
-	private Dictionary labelTable;
-
-	/**
-	 * changeListener
-	 */
-	protected ChangeListener changeListener;
-
-	/**
-	 * changeEvent
-	 */
-	protected transient ChangeEvent changeEvent;
-
-
-	//-------------------------------------------------------------
-	// Initialization ---------------------------------------------
-	//-------------------------------------------------------------
-
-	/**
-	 * Constructor JSlider
-	 */
-	public JSlider() {
-		// TODO
-	} // JSlider()
-
-	/**
-	 * Constructor JSlider
-	 * @param value0 TODO
-	 */
-	public JSlider(int orientation) {
-		// TODO
-	} // JSlider()
-
-	/**
-	 * Constructor JSlider
-	 * @param minimum TODO
-	 * @param maximum TODO
-	 */
-	public JSlider(int minimum, int maximum) {
-		// TODO
-	} // JSlider()
-
-	/**
-	 * Constructor JSlider
-	 * @param minimum TODO
-	 * @param maximum TODO
-	 * @param value TODO
-	 */
-	public JSlider(int minimum, int maximum, int value) {
-		// TODO
-	} // JSlider()
-
-	/**
-	 * Constructor JSlider
-	 * @param orientation TODO
-	 * @param minimum TODO
-	 * @param maximum TODO
-	 * @param value TODO
-	 */
-	public JSlider(int orientation, int minimum, int maximum, int value) {
-		// TODO
-	} // JSlider()
-
-	/**
-	 * Constructor JSlider
-	 * @param value0 TODO
-	 */
-	public JSlider(BoundedRangeModel model) {
-		// TODO
-	} // JSlider()
-
-
-	//-------------------------------------------------------------
-	// Methods ----------------------------------------------------
-	//-------------------------------------------------------------
-
-	/**
-	 * writeObject
-	 * @param stream TODO
-	 * @exception IOException TODO
-	 */
-	private void writeObject(ObjectOutputStream stream) throws IOException {
-		// TODO
-	} // writeObject()
-
-	/**
-	 * getValue
-	 * @returns int
-	 */
-	public int getValue() {
-		return 0; // TODO
-	} // getValue()
-
-	/**
-	 * setValue
-	 * @param value0 TODO
-	 */
-	public void setValue(int value) {
-		// TODO
-	} // setValue()
-
-	/**
-	 * getUI
-	 * @returns SliderUI
-	 */
-	public SliderUI getUI() {
-		return (SliderUI) ui;
-	} // getUI()
-
-	/**
-	 * setUI
-	 * @param ui TODO
-	 */
-	public void setUI(SliderUI ui) {
-		super.setUI(ui);
-	} // setUI()
-
-	/**
-	 * updateUI
-	 */
-	public void updateUI() {
-		setUI((SliderUI) UIManager.get(this));
-		invalidate();
-	} // updateUI()
-
-	/**
-	 * getUIClassID
-	 * @returns String
-	 */
-	public String getUIClassID() {
-		return uiClassID;
-	} // getUIClassID()
-
-	/**
-	 * createChangeListener
-	 * @returns ChangeListener
-	 */
-	protected ChangeListener createChangeListener() {
-		return null; // TODO
-	} // createChangeListener()
-
-	/**
-	 * addChangeListener
-	 * @param listener TODO
-	 */
-	public void addChangeListener(ChangeListener listener) {
-		// TODO
-	} // addChangeListener()
-
-	/**
-	 * removeChangeListener
-	 * @param listener TODO
-	 */
-	public void removeChangeListener(ChangeListener listener) {
-		// TODO
-	} // removeChangeListener()
-
-	/**
-	 * fireStateChanged
-	 */
-	protected void fireStateChanged() {
-		// TODO
-	} // fireStateChanged()
-
-	/**
-	 * getModel
-	 * @returns BoundedRangeModel
-	 */
-	public BoundedRangeModel getModel() {
-		return null; // TODO
-	} // getModel()
-
-	/**
-	 * setModel
-	 * @param model TODO
-	 */
-	public void setModel(BoundedRangeModel model) {
-		// TODO
-	} // setModel()
-
-	/**
-	 * getMinimum
-	 * @returns int
-	 */
-	public int getMinimum() {
-		return 0; // TODO
-	} // getMinimum()
-
-	/**
-	 * setMinimum
-	 * @param minimum TODO
-	 */
-	public void setMinimum(int minimum) {
-		// TODO
-	} // setMinimum()
-
-	/**
-	 * getMaximum
-	 * @returns int
-	 */
-	public int getMaximum() {
-		return 0; // TODO
-	} // getMaximum()
-
-	/**
-	 * setMaximum
-	 * @param maximum TODO
-	 */
-	public void setMaximum(int maximum) {
-		// TODO
-	} // setMaximum()
-
-	/**
-	 * getValueIsAdjusting
-	 * @returns boolean
-	 */
-	public boolean getValueIsAdjusting() {
-		return false; // TODO
-	} // getValueIsAdjusting()
-
-	/**
-	 * setValueIsAdjusting
-	 * @param adjusting TODO
-	 */
-	public void setValueIsAdjusting(boolean adjusting) {
-		// TODO
-	} // setValueIsAdjusting()
-
-	/**
-	 * getExtent
-	 * @returns int
-	 */
-	public int getExtent() {
-		return 0; // TODO
-	} // getExtent()
-
-	/**
-	 * setExtent
-	 * @param vextent TODO
-	 */
-	public void setExtent(int extent) {
-		// TODO
-	} // setExtent()
-
-	/**
-	 * getOrientation
-	 * @returns int
-	 */
-	public int getOrientation() {
-		return 0; // TODO
-	} // getOrientation()
-
-	/**
-	 * setOrientation
-	 * @param orientation TODO
-	 */
-	public void setOrientation(int orientation) {
-		// TODO
-	} // setOrientation()
-
-	/**
-	 * getLabelTable
-	 * @returns Dictionary
-	 */
-	public Dictionary getLabelTable() {
-		return null; // TODO
-	} // getLabelTable()
-
-	/**
-	 * setLabelTable
-	 * @param table TODO
-	 */
-	public void setLabelTable(Dictionary table) {
-		// TODO
-	} // setLabelTable()
-
-	/**
-	 * updateLabelUIs
-	 */
-	protected void updateLabelUIs() {
-		// TODO
-	} // updateLabelUIs()
-
-	/**
-	 * createStandardLabels
-	 * @param increment TODO
-	 * @returns Hashtable
-	 */
-	public Hashtable createStandardLabels(int increment) {
-		return null; // TODO
-	} // createStandardLabels()
-
-	/**
-	 * createStandardLabels
-	 * @param increment TODO
-	 * @param start TODO
-	 * @returns Hashtable
-	 */
-	public Hashtable createStandardLabels(int increment, int start) {
-		return null; // TODO
-	} // createStandardLabels()
-
-	/**
-	 * getInverted
-	 * @returns boolean
-	 */
-	public boolean getInverted() {
-		return false; // TODO
-	} // getInverted()
-
-	/**
-	 * setInverted
-	 * @param inverted TODO
-	 */
-	public void setInverted(boolean inverted) {
-		// TODO
-	} // setInverted()
-
-	/**
-	 * getMajorTickSpacing
-	 * @returns int
-	 */
-	public int getMajorTickSpacing() {
-		return 0; // TODO
-	} // getMajorTickSpacing()
-
-	/**
-	 * setMajorTickSpacing
-	 * @param spacing TODO
-	 */
-	public void setMajorTickSpacing(int spacing) {
-		// TODO
-	} // setMajorTickSpacing()
-
-	/**
-	 * getMinorTickSpacing
-	 * @returns int
-	 */
-	public int getMinorTickSpacing() {
-		return 0; // TODO
-	} // getMinorTickSpacing()
-
-	/**
-	 * setMinorTickSpacing
-	 * @param spacing TODO
-	 */
-	public void setMinorTickSpacing(int spacing) {
-		// TODO
-	} // setMinorTickSpacing()
-
-	/**
-	 * getSnapToTicks
-	 * @returns boolean
-	 */
-	public boolean getSnapToTicks() {
-		return false; // TODO
-	} // getSnapToTicks()
-
-	/**
-	 * getSnapToValue
-	 * @returns boolean
-	 */
-	boolean getSnapToValue() {
-		return false; // TODO
-	} // getSnapToValue()
-
-	/**
-	 * setSnapToTicks
-	 * @param snap TODO
-	 */
-	public void setSnapToTicks(boolean snap) {
-		// TODO
-	} // setSnapToTicks()
-
-	/**
-	 * getPaintTicks
-	 * @returns boolean
-	 */
-	public boolean getPaintTicks() {
-		return false; // TODO
-	} // getPaintTicks()
-
-	/**
-	 * setPaintTicks
-	 * @param paint TODO
-	 */
-	public void setPaintTicks(boolean paint) {
-		// TODO
-	} // setPaintTicks()
-
-	/**
-	 * getPaintTrack
-	 * @returns boolean
-	 */
-	public boolean getPaintTrack() {
-		return false; // TODO
-	} // getPaintTrack()
-
-	/**
-	 * setPaintTrack
-	 * @param paint TODO
-	 */
-	public void setPaintTrack(boolean paint) {
-		// TODO
-	} // setPaintTrack()
-
-	/**
-	 * getPaintLabels
-	 * @returns boolean
-	 */
-	public boolean getPaintLabels() {
-		return false; // TODO
-	} // getPaintLabels()
-
-	/**
-	 * setPaintLabels
-	 * @param paint TODO
-	 */
-	public void setPaintLabels(boolean paint) {
-		// TODO
-	} // setPaintLabels()
-
-	/**
-	 * paramString
-	 * @returns String
-	 */
-	protected String paramString() {
-		return null; // TODO
-	} // paramString()
-
-	/**
-	 * getAccessibleContext
-	 * @returns AccessibleContext
-	 */
-	public AccessibleContext getAccessibleContext() {
-		if (accessibleContext == null) {
-			accessibleContext = new AccessibleJSlider(this);
-		} // if
-		return accessibleContext;
-	} // getAccessibleContext()
-
-
-} // JSlider
+  protected class AccessibleJSlider extends JComponent.AccessibleJComponent
+    implements AccessibleValue
+  {
+    /**
+     * Creates a new AccessibleJSlider object.
+     *
+     * @param value0 DOCUMENT ME!
+     */
+    protected AccessibleJSlider(JSlider value0)
+    {
+      super(value0);
+    }
+
+    /**
+     * DOCUMENT ME!
+     *
+     * @return DOCUMENT ME!
+     */
+    public AccessibleStateSet getAccessibleStateSet()
+    {
+      return null;
+    }
+
+    /**
+     * DOCUMENT ME!
+     *
+     * @return DOCUMENT ME!
+     */
+    public AccessibleRole getAccessibleRole()
+    {
+      return null;
+    }
+
+    /**
+     * DOCUMENT ME!
+     *
+     * @return DOCUMENT ME!
+     */
+    public AccessibleValue getAccessibleValue()
+    {
+      return null;
+    }
+
+    /**
+     * DOCUMENT ME!
+     *
+     * @return DOCUMENT ME!
+     */
+    public Number getCurrentAccessibleValue()
+    {
+      return null;
+    }
+
+    /**
+     * setCurrentAccessibleValue
+     *
+     * @param value0 TODO
+     *
+     * @return boolean
+     */
+    public boolean setCurrentAccessibleValue(Number value0)
+    {
+      return false;
+    }
+
+    /**
+     * getMinimumAccessibleValue
+     *
+     * @return Number
+     */
+    public Number getMinimumAccessibleValue()
+    {
+      return null;
+    }
+
+    /**
+     * getMaximumAccessibleValue
+     *
+     * @return Number
+     */
+    public Number getMaximumAccessibleValue()
+    {
+      return null;
+    }
+  }
+
+  /** Fired in a PropertyChangeEvent when the "inverted" property changes. */
+  public static String INVERTED_CHANGED_PROPERTY = "inverted";
+
+  /** Fired in a PropertyChangeEvent when the "labelTable" property changes. */
+  public static String LABEL_TABLE_CHANGED_PROPERTY = "labelTable";
+
+  /**
+   * Fired in a PropertyChangeEvent when the "majorTickSpacing" property
+   * changes.
+   */
+  public static String MAJOR_TICK_SPACING_CHANGED_PROPERTY = "majorTickSpacing";
+
+  /**
+   * Fired in a PropertyChangeEvent when the "minorTickSpacing" property
+   * changes.
+   */
+  public static String MINOR_TICK_SPACING_CHANGED_PROPERTY = "minorTickSpacing";
+
+  /** Fired in a PropertyChangeEvent when the "model" property changes. */
+  public static String MODEL_CHANGED_PROPERTY = "model";
+
+  /** Fired in a PropertyChangeEvent when the "orientation" property changes. */
+  public static String ORIENTATION_CHANGED_PROPERTY = "orientation";
+
+  /** Fired in a PropertyChangeEvent when the "paintLabels" property changes. */
+  public static String PAINT_LABELS_CHANGED_PROPERTY = "paintLabels";
+
+  /** Fired in a PropertyChangeEvent when the "paintTicks" property changes. */
+  public static String PAINT_TICKS_CHANGED_PROPERTY = "paintTicks";
+
+  /** Whether or not this slider paints its ticks. */
+  private transient boolean paintTicks = false;
+
+  /** 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 = false;
+
+  /**
+   * 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;
+
+  /** A list of all ChangeListeners listening to this slider. */
+  private transient EventListenerList changeListenerList;
+
+  /** The model used to describe the slider. */
+  protected BoundedRangeModel sliderModel;
+
+  /** The space between major ticks. */
+  protected int majorTickSpacing;
+
+  /** The space between minor ticks. */
+  protected int minorTickSpacing;
+
+  /** Whether the slider snaps its values to ticks. */
+  protected boolean snapToTicks = true;
+
+  /** The orientation of the slider. */
+  protected int orientation = HORIZONTAL;
+
+  /** The ChangeListener that listens to the model. */
+  protected ChangeListener changeListener;
+
+  /** The ChangeEvent that is passed to all listeners of this slider. */
+  protected transient ChangeEvent changeEvent;
+
+  /**
+   * Creates a new horizontal JSlider object with a minimum of 0, a maximum of
+   * 100, and a value of 50.
+   */
+  public JSlider()
+  {
+    this(HORIZONTAL, 0, 100, 50);
+  }
+
+  /**
+   * Creates a new JSlider object 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.
+   */
+  public JSlider(int orientation)
+  {
+    this(orientation, 0, 100, 50);
+  }
+
+  /**
+   * Creates a new horizontal JSlider object with the given maximum and
+   * minimum and a value that is  halfway between the minimum and the
+   * maximum.
+   *
+   * @param minimum The minimum value of the JSlider.
+   * @param maximum The maximum value of the JSlider.
+   */
+  public JSlider(int minimum, int maximum)
+  {
+    this(HORIZONTAL, minimum, maximum, (maximum - minimum) / 2);
+  }
+
+  /**
+   * Creates a new horizontal JSlider object with the given minimum, maximum,
+   * and value.
+   *
+   * @param minimum The minimum value of the JSlider.
+   * @param maximum The maximum value of the JSlider.
+   * @param value The initial value of the JSlider.
+   */
+  public JSlider(int minimum, int maximum, int value)
+  {
+    this(HORIZONTAL, minimum, maximum, value);
+  }
+
+  /**
+   * Creates a new JSlider object with the given orientation, minimum,
+   * maximum, and value.
+   *
+   * @param orientation The orientation of the JSlider.
+   * @param minimum The minimum value of the JSlider.
+   * @param maximum The maximum value of the JSlider.
+   * @param value The initial value of the JSlider.
+   */
+  public JSlider(int orientation, int minimum, int maximum, int value)
+  {
+    sliderModel = new DefaultBoundedRangeModel(value, 0, minimum, maximum);
+    if (orientation == HORIZONTAL || orientation == VERTICAL)
+      this.orientation = orientation;        
+    changeListener = createChangeListener();
+    changeListenerList = new EventListenerList();
+    sliderModel.addChangeListener(changeListener);
+    updateUI();
+  }
+
+  /**
+   * Creates a new horizontal JSlider object with the given model.
+   *
+   * @param model The model the slider will be created with.
+   */
+  public JSlider(BoundedRangeModel model)
+  {
+    if (model == null)
+      sliderModel = new DefaultBoundedRangeModel(50, 0, 0, 100);
+    else
+      sliderModel = model;
+    changeListener = createChangeListener();
+    changeListenerList = new EventListenerList();
+    sliderModel.addChangeListener(changeListener);
+    updateUI();
+  }
+
+  /**
+   * This method returns the current value of the slider.
+   *
+   * @return The value of the slider stored in the model.
+   */
+  public int getValue()
+  {
+    return sliderModel.getValue();
+  }
+
+  /**
+   * This method sets the value of the slider.
+   *
+   * @param value The slider's new value.
+   */
+  public void setValue(int value)
+  {
+    sliderModel.setValue(value);
+  }
+
+  /**
+   * This method returns the slider's UI delegate.
+   *
+   * @return The slider's UI delegate.
+   */
+  public SliderUI getUI()
+  {
+    return (SliderUI) ui;
+  }
+
+  /**
+   * This method sets the slider's UI delegate.
+   *
+   * @param ui A SliderUI object to use with this slider.
+   */
+  public void setUI(SliderUI ui)
+  {
+    super.setUI(ui);
+  }
+
+  /**
+   * This method sets this slider's UI to the UIManager's default for the
+   * current look and feel.
+   */
+  public void updateUI()
+  {
+    setUI((SliderUI) UIManager.getUI(this));
+    invalidate();
+    repaint();
+  }
+
+  /**
+   * This method returns a name to identify which look and feel class will be
+   * the UI delegate for the slider.
+   *
+   * @return The L&F classID. "SliderUI"
+   */
+  public String getUIClassID()
+  {
+    return "SliderUI";
+  }
+
+  /**
+   * Creates a ChangeListener for this Slider.
+   *
+   * @return A new ChangeListener.
+   */
+  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();
+	}
+      };
+  }
+
+  /**
+   * This method registers a listener to this slider. The listener will be
+   * informed of new ChangeEvents.
+   *
+   * @param listener The listener to register.
+   */
+  public void addChangeListener(ChangeListener listener)
+  {
+    changeListenerList.add(ChangeListener.class, listener);
+  }
+
+  /**
+   * This method removes a listener from this slider.
+   *
+   * @param listener The listener to remove.
+   */
+  public void removeChangeListener(ChangeListener listener)
+  {
+    changeListenerList.remove(ChangeListener.class, listener);
+  }
+
+  /**
+   * This method is called whenever the model fires a ChangeEvent. It should
+   * propagate the ChangeEvent to its listeners with a new ChangeEvent that
+   * identifies the slider as the source.
+   */
+  protected void fireStateChanged()
+  {
+    Object[] changeListeners = changeListenerList.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);
+      }
+  }
+
+  /**
+   * This method returns an array of all ChangeListeners listening to this
+   * slider.
+   *
+   * @return An array of ChangeListeners listening to this slider.
+   */
+  public ChangeListener[] getChangeListener()
+  {
+    return (ChangeListener[]) changeListenerList.getListenerList();
+  }
+
+  /**
+   * This method returns the model of the slider.
+   *
+   * @return The slider's model.
+   */
+  public BoundedRangeModel getModel()
+  {
+    return sliderModel;
+  }
+
+  /**
+   * This method changes the "model" property. It also needs  to unregister
+   * any listeners to the old model and register any listeners to the new
+   * model.
+   *
+   * @param model The model to use with the slider.
+   */
+  public void setModel(BoundedRangeModel model)
+  {
+    //XXX: The spec doesn't not allow us to set the model to null, but
+    //it will throw a null pointer exception. Better to ignore
+    //attempts to set the model to null?
+    if (model != sliderModel && model != null)
+      {
+	BoundedRangeModel oldModel = sliderModel;
+	sliderModel = model;
+        oldModel.removeChangeListener(changeListener);
+        sliderModel.addChangeListener(changeListener);
+	firePropertyChange(MODEL_CHANGED_PROPERTY, oldModel, sliderModel);
+      }
+  }
+
+  /**
+   * This method returns the minimum value of the slider.
+   *
+   * @return The minimum value of the slider.
+   */
+  public int getMinimum()
+  {
+    return sliderModel.getMinimum();
+  }
+
+  /**
+   * This method sets the minimum value of the slider.
+   *
+   * @param minimum The minimum value of the slider.
+   */
+  public void setMinimum(int minimum)
+  {
+    sliderModel.setMinimum(minimum);
+  }
+
+  /**
+   * This method returns the maximum value of the slider.
+   *
+   * @return The maximum value of the slider.
+   */
+  public int getMaximum()
+  {
+    return sliderModel.getMaximum();
+  }
+
+  /**
+   * This method sets the maximum value of the slider.
+   *
+   * @param maximum The maximum value of the slider.
+   */
+  public void setMaximum(int maximum)
+  {
+    sliderModel.setMaximum(maximum);
+  }
+
+  /**
+   * This method returns this slider's isAdjusting value.
+   *
+   * @return The slider's isAdjusting value.
+   */
+  public boolean getValueIsAdjusting()
+  {
+    return sliderModel.getValueIsAdjusting();
+  }
+
+  /**
+   * This method sets the isAdjusting value for the slider.
+   *
+   * @param adjusting The slider's isAdjusting value.
+   */
+  public void setValueIsAdjusting(boolean adjusting)
+  {
+    sliderModel.setValueIsAdjusting(adjusting);
+  }
+
+  /**
+   * This method returns the extent value for this slider.
+   *
+   * @return The extent value for this slider.
+   */
+  public int getExtent()
+  {
+    return sliderModel.getExtent();
+  }
+
+  /**
+   * This method sets the extent value for this slider.
+   *
+   * @param extent The extent value for this slider.
+   */
+  public void setExtent(int extent)
+  {
+    sliderModel.setExtent(extent);
+  }
+
+  /**
+   * This method returns the slider orientation.
+   *
+   * @return The orientation of the slider.
+   */
+  public int getOrientation()
+  {
+    return orientation;
+  }
+
+  /**
+   * This method changes the "orientation" property of this slider. If the
+   * orientation is not VERTICAL or HORIZONTAL, this method does nothing.
+   *
+   * @param orientation The orientation of this slider.
+   */
+  public void setOrientation(int orientation)
+  {
+    if (orientation != VERTICAL && orientation != HORIZONTAL)
+      return;
+    if (orientation != this.orientation)
+      {
+	int oldOrientation = this.orientation;
+	this.orientation = orientation;
+	firePropertyChange(ORIENTATION_CHANGED_PROPERTY, oldOrientation,
+	                   this.orientation);
+      }
+  }
+
+  /**
+   * This method returns the label table for this slider.
+   *
+   * @return The label table for this slider.
+   */
+  public Dictionary getLabelTable()
+  {
+    return labelTable;
+  }
+
+  /**
+   * This method changes the "labelTable" property of this slider.
+   *
+   * @param table The label table for this slider.
+   */
+  public void setLabelTable(Dictionary table)
+  {
+    if (table != labelTable)
+      {
+	Dictionary oldTable = labelTable;
+	labelTable = table;
+	firePropertyChange(LABEL_TABLE_CHANGED_PROPERTY, oldTable, labelTable);
+      }
+  }
+
+  /**
+   * This method is called to reset UI delegates for the labels in the
+   * labelTable to a default for the current look and feel.
+   */
+  protected void updateLabelUIs()
+  {
+    if (labelTable == null)
+      return;
+    for (Enumeration list = labelTable.elements(); list.hasMoreElements();)
+      {
+	JLabel label = (JLabel) list.nextElement();
+	label.updateUI();
+      }
+  }
+
+  /**
+   * Creates a hashtable of (Integer, JLabel) pairs that can be used as a
+   * label table for this slider. The labels will start from the sliders
+   * minimum and increase by the increment. Each  label will have a text
+   * string indicating their integer value.
+   *
+   * @param increment The increment to between labels.
+   *
+   * @return A hashtable with the labels and their keys.
+   */
+  public Hashtable createStandardLabels(int increment)
+  {
+    return createStandardLabels(increment, sliderModel.getMinimum());
+  }
+
+  /**
+   * Creates a hashtable of (Integer, JLabel) 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 their integer value.
+   *
+   * @param increment The increment to between labels.
+   * @param start The value to start from.
+   *
+   * @return A hashtable with the labels and their keys.
+   */
+  public Hashtable createStandardLabels(int increment, int start)
+  {
+    Hashtable table = new Hashtable();
+    JLabel label;
+
+    int max = sliderModel.getMaximum();
+
+    for (int i = start; i <= max; i += increment)
+      {
+	label = new JLabel(String.valueOf(i));
+	label.setVerticalAlignment(CENTER);
+	label.setHorizontalAlignment(CENTER);
+	label.setBounds(0, 0, 20, 15);
+	table.put(new Integer(i), label);
+      }
+    return table;
+  }
+
+  /**
+   * This method returns whether the slider is inverted. Horizontal sliders
+   * that are not inverted will have the minimums on the left. If they are
+   * inverted, the minimums will be  on the right. Vertical sliders that are
+   * not inverted will have the minimums at the bottom. If they are inverted,
+   * the minimums will be at the top.
+   *
+   * @return Whether this slider is inverted.
+   */
+  public boolean getInverted()
+  {
+    return (getComponentOrientation() != ComponentOrientation.LEFT_TO_RIGHT);
+  }
+
+  /**
+   * This method changes the "inverted" property for this slider.Horizontal
+   * sliders  that are not inverted will have the minimums on the left. If
+   * they are inverted, the minimums will be  on the right. Vertical sliders
+   * that are not inverted will have the minimums at the bottom. If they are
+   * inverted, the minimums will be at the top.
+   *
+   * @param inverted Whether the slider should be inverted.
+   */
+  public void setInverted(boolean inverted)
+  {
+    boolean isInverted = getInverted();
+    if (isInverted != inverted)
+      {
+	boolean oldInverted = isInverted;
+	isInverted = inverted;
+	setComponentOrientation((isInverted)
+	                        ? ComponentOrientation.RIGHT_TO_LEFT
+	                        : ComponentOrientation.LEFT_TO_RIGHT);
+	firePropertyChange(INVERTED_CHANGED_PROPERTY, oldInverted, isInverted);
+      }
+  }
+
+  /**
+   * This method returns the amount of units between each major tick mark.
+   *
+   * @return The amount of units between each major tick mark.
+   */
+  public int getMajorTickSpacing()
+  {
+    return majorTickSpacing;
+  }
+
+  /**
+   * This method changes the "majorTickSpacing" property for this slider. The
+   * major tick spacing is the amount of units between each major tick mark.
+   *
+   * @param spacing The amount of units between each major tick mark.
+   */
+  public void setMajorTickSpacing(int spacing)
+  {
+    if (majorTickSpacing != spacing)
+      {
+	int oldSpacing = majorTickSpacing;
+	majorTickSpacing = spacing;
+	firePropertyChange(MAJOR_TICK_SPACING_CHANGED_PROPERTY, oldSpacing,
+	                   majorTickSpacing);
+      }
+  }
+
+  /**
+   * This method returns the amount of units between each minor tick mark.
+   *
+   * @return The amount of units between each minor tick mark.
+   */
+  public int getMinorTickSpacing()
+  {
+    return minorTickSpacing;
+  }
+
+  /**
+   * This method changes the "minorTickSpacing" property for this slider. The
+   * minor tick spacing is the amount of units between each minor tick mark.
+   *
+   * @param spacing The amount of units between each minor tick mark.
+   */
+  public void setMinorTickSpacing(int spacing)
+  {
+    if (minorTickSpacing != spacing)
+      {
+	int oldSpacing = minorTickSpacing;
+	minorTickSpacing = spacing;
+	firePropertyChange(MINOR_TICK_SPACING_CHANGED_PROPERTY, oldSpacing,
+	                   minorTickSpacing);
+      }
+  }
+
+  /**
+   * This method returns whether this slider is snapping to ticks.  Sliders
+   * that snap to ticks will automatically move the thumb to the nearest tick
+   * mark.
+   *
+   * @return Whether this slider snaps to ticks.
+   */
+  public boolean getSnapToTicks()
+  {
+    return snapToTicks;
+  }
+
+  /**
+   * This method sets whether this slider will snap to ticks. Sliders that
+   * snap to ticks will automatically move the thumb to the nearest tick
+   * mark.
+   *
+   * @param snap Whether this slider snaps to ticks.
+   */
+  public void setSnapToTicks(boolean snap)
+  {
+    if (snap != snapToTicks)
+      {
+	snapToTicks = snap;
+	fireStateChanged();
+      }
+  }
+
+  /**
+   * This method returns whether the slider will paint its tick marks. In
+   * addition to setting this property to true, one of minor tick spacing  or
+   * major tick spacing must be set to a value greater than 0 in order for
+   * ticks to be painted.
+   *
+   * @return Whether ticks will be painted.
+   */
+  public boolean getPaintTicks()
+  {
+    return paintTicks;
+  }
+
+  /**
+   * This method changes the "paintTicks" property for this slider. In
+   * addition to setting this property to true, one of minor tick spacing  or
+   * major tick spacing must be set to a value greater than 0 in order for
+   * ticks to be painted.
+   *
+   * @param paint Whether ticks will be painted.
+   */
+  public void setPaintTicks(boolean paint)
+  {
+    if (paint != paintTicks)
+      {
+	boolean oldPaintTicks = paintTicks;
+	paintTicks = paint;
+	firePropertyChange(PAINT_TICKS_CHANGED_PROPERTY, oldPaintTicks,
+	                   paintTicks);
+      }
+  }
+
+  /**
+   * This method returns whether the track will be painted.
+   *
+   * @return Whether the track will be painted.
+   */
+  public boolean getPaintTrack()
+  {
+    return paintTrack;
+  }
+
+  /**
+   * This method sets whether the track will be painted.
+   *
+   * @param paint Whether the track will be painted.
+   */
+  public void setPaintTrack(boolean paint)
+  {
+    paintTrack = paint;
+  }
+
+  /**
+   * This method returns whether labels will be painted.
+   *
+   * @return Whether labels will be painted.
+   */
+  public boolean getPaintLabels()
+  {
+    return paintLabels;
+  }
+
+  /**
+   * This method changes the "paintLabels" property.
+   *
+   * @param paint Whether labels will be painted.
+   */
+  public void setPaintLabels(boolean paint)
+  {
+    if (paint != paintLabels)
+      {
+	boolean oldPaintLabels = paintLabels;
+	paintLabels = paint;
+	firePropertyChange(PAINT_LABELS_CHANGED_PROPERTY, oldPaintLabels,
+	                   paintLabels);
+      }
+  }
+
+  /**
+   * This method is used primarily for debugging purposes and returns a string
+   * that can be used to represent this slider.
+   *
+   * @return A string representing this slider.
+   */
+  protected String paramString()
+  {
+    return "JSlider";
+  }
+
+  /**
+   * DOCUMENT ME!
+   *
+   * @return DOCUMENT ME!
+   */
+  public AccessibleContext getAccessibleContext()
+  {
+    if (accessibleContext == null)
+      accessibleContext = new AccessibleJSlider(this);
+    return accessibleContext;
+  }
+}
Index: javax/swing/SwingUtilities.java
===================================================================
RCS file: /cvs/gcc/gcc/libjava/javax/swing/SwingUtilities.java,v
retrieving revision 1.6
diff -u -r1.6 SwingUtilities.java
--- javax/swing/SwingUtilities.java	12 Feb 2004 00:17:23 -0000	1.6
+++ javax/swing/SwingUtilities.java	13 Feb 2004 15:22:29 -0000
@@ -48,6 +48,7 @@
 import java.awt.Insets;
 import java.awt.Point;
 import java.awt.Rectangle;
+import java.awt.Shape;
 import java.awt.Toolkit;
 import java.awt.Window;
 import java.awt.event.KeyEvent;
@@ -667,7 +668,7 @@
     else
       {
         iconR.width = icon.getIconWidth();
-        iconR.height = icon.getIconWidth();
+        iconR.height = icon.getIconHeight();
       }
     textR.width = fm.stringWidth(text);
     textR.height = fm.getHeight(); 
@@ -776,5 +777,53 @@
   {
     return java.awt.EventQueue.isDispatchThread();
   }
+  
+  /**
+   * This method paints the given component at the given position and size.
+   * The component will be reparented to the container given.
+   * 
+   * @param g The Graphics object to draw with.
+   * @param c The Component to draw
+   * @param p The Container to reparent to.
+   * @param x The x coordinate to draw at.
+   * @param y The y coordinate to draw at.
+   * @param w The width of the drawing area.
+   * @param h The height of the drawing area.
+   */
+  public static void paintComponent(Graphics g, Component c, Container p, 
+                                    int x, int y, int w, int h)
+  {       
+    Component parent = c.getParent();
+    if (parent != null)
+      parent.remove(c);
+    if (p != null)
+      p.add(c);
+    
+    Shape savedClip = g.getClip();
+    
+    g.setClip(x, y, w, h);
+    g.translate(x, y);
+
+    c.paint(g);
+    
+    g.translate(-x, -y);
+    g.setClip(savedClip);
+  }
+
+  /**
+   * This method paints the given component in the given rectangle.
+   * The component will be reparented to the container given.
+   * 
+   * @param g The Graphics object to draw with.
+   * @param c The Component to draw
+   * @param p The Container to reparent to.
+   * @param r The rectangle that describes the drawing area.
+   */  
+  public static void paintComponent(Graphics g, Component c, 
+                                    Container p, Rectangle r)
+  {
+    paintComponent(g, c, p, r.x, r.y, r.width, r.height);
+  }
+  
 
 }
Index: javax/swing/plaf/basic/BasicLookAndFeel.java
===================================================================
RCS file: /cvs/gcc/gcc/libjava/javax/swing/plaf/basic/BasicLookAndFeel.java,v
retrieving revision 1.4
diff -u -r1.4 BasicLookAndFeel.java
--- javax/swing/plaf/basic/BasicLookAndFeel.java	12 Feb 2004 00:17:24 -0000	1.4
+++ javax/swing/plaf/basic/BasicLookAndFeel.java	13 Feb 2004 15:22:29 -0000
@@ -663,6 +663,9 @@
       "Slider.foreground", new ColorUIResource(Color.lightGray),
       "Slider.highlight", new ColorUIResource(Color.white),
       "Slider.shadow", new ColorUIResource(Color.gray),
+      "Slider.thumbHeight", new Integer(20),
+      "Slider.thumbWidth", new Integer(10),
+      "Slider.tickHeight", new Integer(12),
       "SplitPane.ancestorInputMap", new UIDefaults.LazyInputMap(new Object[] {
         "F6",  "toggleFocus",
         "F8",  "startResize",
Index: javax/swing/plaf/basic/BasicSliderUI.java
===================================================================
RCS file: javax/swing/plaf/basic/BasicSliderUI.java
diff -N javax/swing/plaf/basic/BasicSliderUI.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ javax/swing/plaf/basic/BasicSliderUI.java	13 Feb 2004 15:22:30 -0000
@@ -0,0 +1,2116 @@
+/* BasicSliderUI.java
+   Copyright (C) 2004 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., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 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.plaf.basic;
+
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Container;
+import java.awt.Dimension;
+import java.awt.Graphics;
+import java.awt.Insets;
+import java.awt.Point;
+import java.awt.Polygon;
+import java.awt.Rectangle;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.ComponentAdapter;
+import java.awt.event.ComponentEvent;
+import java.awt.event.ComponentListener;
+import java.awt.event.FocusEvent;
+import java.awt.event.FocusListener;
+import java.awt.event.InputEvent;
+import java.awt.event.MouseEvent;
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+import java.util.Dictionary;
+import java.util.Enumeration;
+import javax.swing.JButton;
+import javax.swing.JComponent;
+import javax.swing.JLabel;
+import javax.swing.JSlider;
+import javax.swing.KeyStroke;
+import javax.swing.SwingUtilities;
+import javax.swing.Timer;
+import javax.swing.UIDefaults;
+import javax.swing.UIManager;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+import javax.swing.event.MouseInputAdapter;
+import javax.swing.plaf.ComponentUI;
+import javax.swing.plaf.SliderUI;
+
+
+/**
+ *<p>
+ * BasicSliderUI.java
+ *
+ * This is the UI delegate in the Basic look and feel that
+ * paints JSliders.
+ * </p>
+ * <p>
+ * The UI delegate keeps track of 6 rectangles that place
+ * the various parts of the JSlider inside the component. 
+ * </p>
+ * <p>
+ * The rectangles are organized as follows:
+ * </p>
+ * <pre>
+ *
+ *     +----------------------------------------------------------+ <-- focusRect
+ *     |                                                          |
+ *     |  +==+-------------------+==+-----------------------+==+<------ contentRect
+ *     |  |  |                   |  |<---thumbRect          |  |  |
+ *     |  |  |    TRACK          |  |                       |<--------- trackRect
+ *     |  |  +-------------------+==+-----------------------+  |  |
+ *     |  |  |                                              |  |  |
+ *     |  |  |          TICKS GO HERE                       |<-------- tickRect
+ *     |  |  |                                              |  |  |
+ *     |  +==+----------------------------------------------+==+  |
+ *     |  |  |                                              |  |  |
+ *     |  |  |                                              |  |<----- labelRect
+ *     |  |  |                 LABELS GO HERE               |  |  |
+ *     |  |  |                                              |  |  |
+ *     |  |  |                                              |  |  |
+ *     |  |  |                                              |  |  |
+ *     |  |  |                                              |  |  |
+ *     |  |                                                 |  |  |
+ * </pre>
+ * <p>
+ *   The space between the <code>contentRect</code> and the <code>focusRect</code> are the <code>FocusInsets</code>.
+ * </p>
+ * <p>
+ *   The space between the <code>focusRect</code> and the component bounds is the <code>insetCache</code>
+ *   which are the component's insets.
+ * </p>
+ * <p>
+ *   The top of the thumb is the top of the <thumb>contentRect</code>.
+ *   The <code>trackRect</code> has to be as tall as the thumb.
+ * </p>
+ * <p>
+ *   The <code>trackRect</code> and <code>tickRect</code> do not start from the left edge of
+ *   the <code>focusRect</code>. They are <code>trackBuffer</code> away from each side of the
+ *   <code>focusRect</code>. This is so that the thumb has room to move.
+ * </p>
+ * <p>
+ *   The <code>labelRect</code> does start right against the <code>contentRect</code>'s left and right
+ *   edges and it gets all remaining space.
+ * </p>
+ */
+public class BasicSliderUI extends SliderUI
+{
+  /**
+   * Helper class that listens to the {@link JSlider}'s model for changes.
+   */
+  protected class ChangeHandler implements ChangeListener
+  {
+    /**
+     * Called when the slider's model has been altered. The UI delegate should
+     * recalculate any rectangles that are dependent on the model for their
+     * positions and repaint.
+     *
+     * @param e A static {@link ChangeEvent} passed from the model.
+     */
+    public void stateChanged(ChangeEvent e)
+    {
+      //Maximum, minimum, and extent values will be taken
+      //care of automatically when the slider is repainted.
+      calculateThumbLocation();
+      slider.repaint();
+    }
+  }
+
+  /**
+   * Helper class that listens for resize events.
+   */
+  protected class ComponentHandler extends ComponentAdapter
+  {
+    /**
+     * Called when the size of the component changes. The UI delegate should
+     * recalculate any rectangles that are dependent on the model for their positions
+     * and repaint.
+     *
+     * @param e A {@link ComponentEvent}.
+     */
+    public void componentResized(ComponentEvent e)
+    {
+      //The component being resized is equivalent to 
+      //our insets changing.
+      recalculateIfInsetsChanged();
+
+      slider.revalidate();
+      slider.repaint();
+    }
+  }
+
+  /**
+   * Helper class that listens for focus events.
+   */
+  protected class FocusHandler implements FocusListener
+  {
+    /**
+     * Called when the {@link JSlider} has gained focus. 
+     * It should repaint the slider with the focus drawn.
+     *
+     * @param e A {@link FocusEvent}.
+     */
+    public void focusGained(FocusEvent e)
+    {
+    }
+
+    /**
+     * Called when the {@link JSlider} has lost focus. It 
+     * should repaint the slider without the focus drawn.
+     *
+     * @param e A {@link FocusEvent}.
+     */
+    public void focusLost(FocusEvent e)
+    {
+    }
+  }
+
+  /**
+   * Helper class that listens for changes to the properties of the {@link
+   * JSlider}.
+   */
+  protected class PropertyChangeHandler implements PropertyChangeListener
+  {
+    /**
+     * Called when one of the properties change. The UI should recalculate any
+     * rectangles if necessary and repaint.
+     *
+     * @param e A {@link PropertyChangeEvent}.
+     */
+    public void propertyChange(PropertyChangeEvent e)
+    {
+      //Check for orientation changes.
+      if (e.getPropertyName().equals(JSlider.ORIENTATION_CHANGED_PROPERTY))
+	recalculateIfOrientationChanged();
+      //and check for inversion changes so we can cache the value.
+      else if (e.getPropertyName().equals(JSlider.INVERTED_CHANGED_PROPERTY))
+        leftToRightCache = !slider.getInverted();	
+      slider.repaint();
+    }
+  }
+
+  /**
+   * Helper class that listens to our swing timer. This class is responsible for
+   * listening to the timer and moving the thumb in the proper direction
+   * every interval.
+   */
+  protected class ScrollListener implements ActionListener
+  {
+    /** Indicates which direction the thumb should scroll. */
+    private transient int direction;
+
+    /** Indicates whether we should scroll in blocks or in units. */
+    private transient boolean block;
+
+    /**
+     * Creates a new ScrollListener object.
+     */
+    public ScrollListener()
+    {
+      direction = POSITIVE_SCROLL;
+      block = false;
+    }
+
+    /**
+     * Creates a new ScrollListener object.
+     *
+     * @param dir The direction to scroll in.
+     * @param block If movement will be in blocks.
+     */
+    public ScrollListener(int dir, boolean block)
+    {
+      direction = dir;
+      this.block = block;
+    }
+
+    /**
+     * Called every time the swing timer reaches its interval. If the thumb
+     * needs to move, then this method will move the thumb one block or 
+     * unit in the direction desired. Otherwise, the timer can be stopped.
+     *
+     * @param e An {@link ActionEvent}.
+     */
+    public void actionPerformed(ActionEvent e)
+    {
+      //FIXME: When you drag the mouse in the opposite direction again 
+      //past the thumb, the thumb should stop.
+      int timerStopValue;
+      if (slider.getOrientation() == JSlider.HORIZONTAL)
+	timerStopValue = valueForXPosition(trackListener.currentMouseX);
+      else
+	timerStopValue = valueForYPosition(trackListener.currentMouseY);
+
+      if (!trackListener.shouldScroll(direction))
+        {
+	  scrollTimer.stop();
+	  return;
+        }
+
+      if (block)
+	scrollByBlock(direction);
+      else
+	scrollByUnit(direction);
+    }
+
+    /**
+     * Sets the direction to scroll in.
+     *
+     * @param direction The direction to scroll in.
+     */
+    public void setDirection(int direction)
+    {
+      this.direction = direction;
+    }
+
+    /**
+     * Sets whether movement will be in blocks.
+     *
+     * @param block If movement will be in blocks.
+     */
+    public void setScrollByBlock(boolean block)
+    {
+      this.block = block;
+    }
+  }
+
+  /**
+   * Helper class that listens for mouse events.
+   */
+  protected class TrackListener extends MouseInputAdapter
+  {
+    /** The current X position of the mouse. */
+    protected int currentMouseX;
+
+    /** The current Y position of the mouse. */
+    protected int currentMouseY;
+
+    /** FIXME: Figure out what this is used for. */
+    protected int offset;
+
+    /**
+     * Called when the mouse has been dragged. This should find the mouse's
+     * current position and adjust the value of the {@link JSlider}
+     * accordingly.
+     *
+     * @param e A {@link MouseEvent}
+     */
+    public void mouseDragged(MouseEvent e)
+    {
+      //FIXME: When we receive dragging events, fix this.
+    }
+
+    /**
+     * Called when the mouse has moved over a component but no buttons have
+     * been pressed yet.
+     *
+     * @param e A {@link MouseEvent}
+     */
+    public void mouseMoved(MouseEvent e)
+    {
+      //FIXME: When we receive mouve events, fix this.
+    }
+
+    /**
+     * Called when the mouse is pressed. When the press occurs on the thumb
+     * itself, the {@link JSlider} should have its value set to where the
+     * mouse was pressed. If the press occurs on the track, then the thumb
+     * should move one block towards the direction of the mouse.
+     *
+     * @param e A {@link MouseEvent}
+     */
+    public void mousePressed(MouseEvent e)
+    {
+      currentMouseX = e.getX();
+      currentMouseY = e.getY();
+
+      int value;
+      if (slider.getOrientation() == JSlider.HORIZONTAL)
+	value = valueForXPosition(currentMouseX);
+      else
+	value = valueForYPosition(currentMouseY);
+
+      if (slider.getSnapToTicks())
+	value = findClosestTick(value);
+
+      if (value == slider.getValue())
+	return;
+
+      // If the thumb is hit, then we don't need to set the timers to move it. 
+      if (thumbRect.contains(e.getPoint()))
+	slider.setValue(value);
+      else
+        {
+	  // The mouse has hit some other part of the slider.
+	  // The value moves no matter where in the slider you hit.
+	  if (value > slider.getValue())
+	    scrollDueToClickInTrack(POSITIVE_SCROLL);
+	  else
+	    scrollDueToClickInTrack(NEGATIVE_SCROLL);
+        }
+    }
+
+    /**
+     * Called when the mouse is released.  This should stop the timer that
+     * scrolls the thumb.
+     *
+     * @param e A {@link MouseEvent}
+     */
+    public void mouseReleased(MouseEvent e)
+    {
+      currentMouseX = e.getX();
+      currentMouseY = e.getY();
+
+      if (scrollTimer != null)
+	scrollTimer.stop();
+    }
+
+    /**
+     * Indicates whether the thumb should scroll in the given direction.
+     *
+     * @param direction The direction to check.
+     *
+     * @return True if the thumb should move in that direction.
+     */
+    public boolean shouldScroll(int direction)
+    {
+      int value;
+      if (slider.getOrientation() == JSlider.HORIZONTAL)
+	value = valueForXPosition(currentMouseX);
+      else
+	value = valueForYPosition(currentMouseY);
+
+      if (direction == POSITIVE_SCROLL)
+	return (value > slider.getValue());
+      else
+	return (value < slider.getValue());
+    }
+  }
+
+  /** The preferred height of the thumb. */
+  private transient int thumbHeight;
+
+  /** The preferred width of the thumb. */
+  private transient int thumbWidth;
+
+  /** The preferred height of the tick rectangle. */
+  private transient int tickHeight;
+
+  /** Listener for changes from the model. */
+  protected ChangeListener changeListener;
+
+  /** Listener for changes to the {@link JSlider}. */
+  protected PropertyChangeListener propertyChangeListener;
+
+  /** Listener for the scrollTimer. */
+  protected ScrollListener scrollListener;
+
+  /** Listener for component resizing. */
+  protected ComponentListener componentListener;
+
+  /** Listener for focus handling. */
+  protected FocusListener focusListener;
+
+  /** Listener for mouse events. */
+  protected TrackListener trackListener;
+
+  /** The insets between the FocusRectangle and the ContentRectangle. */
+  protected Insets focusInsets;
+
+  /** The {@link JSlider}'s insets. */
+  protected Insets insetCache;
+
+  /** Rectangle describing content bounds. See diagram above. */
+  protected Rectangle contentRect;
+
+  /** Rectangle describing focus bounds. See diagram above. */
+  protected Rectangle focusRect;
+
+  /** Rectangle describing the thumb's bounds. See diagram above. */
+  protected Rectangle thumbRect;
+
+  /** Rectangle describing the tick bounds. See diagram above. */
+  protected Rectangle tickRect;
+
+  /** Rectangle describing the label bounds. See diagram above. */
+  protected Rectangle labelRect;
+
+  /** Rectangle describing the track bounds. See diagram above. */
+  protected Rectangle trackRect;
+
+  /** FIXME: use this somewhere. */
+  public static final int MAX_SCROLL = 2;
+
+  /** FIXME: use this somewhere. */
+  public static final int MIN_SCROLL = -2;
+
+  /** A constant describing scrolling towards the minimum. */
+  public static final int NEGATIVE_SCROLL = -1;
+
+  /** A constant describing scrolling towards the maximum. */
+  public static final int POSITIVE_SCROLL = 1;
+
+  /** The gap between the edges of the contentRect and trackRect. */
+  protected int trackBuffer;
+
+  /** A cached value of the slider's LEFT_TO_RIGHT orientation. */
+  protected boolean leftToRightCache;
+
+  /** A timer that periodically moves the thumb. */
+  protected Timer scrollTimer;
+
+  /** A reference to the {@link JSlider} that this UI was created for. */
+  protected JSlider slider;
+
+  /** The shadow color. */
+  private transient Color shadowColor;
+  
+  /** The highlight color. */
+  private transient Color highlightColor;
+  
+  /** The focus color. */
+  private transient Color focusColor;
+  
+  /**
+   * Creates a new Basic look and feel Slider UI.
+   *
+   * @param b The {@link JSlider} that this UI was created for.
+   */
+  public BasicSliderUI(JSlider b)
+  {
+    super();
+  }
+
+  /**
+   * Gets the shadow color to be used for this slider. The shadow color is the
+   * color used for drawing the top and left edges of the track.
+   *
+   * @return The shadow color.
+   */
+  protected Color getShadowColor()
+  {
+    return shadowColor;
+  }
+
+  /**
+   * Gets the highlight color to be used for this slider. The highlight color
+   * is the color used for drawing the bottom and right edges of the track.
+   *
+   * @return The highlight color.
+   */
+  protected Color getHighlightColor()
+  {
+    return highlightColor;
+  }
+
+  /**
+   * Gets the focus color to be used for this slider. The focus color is the
+   * color used for drawing the focus rectangle when the component gains
+   * focus.
+   *
+   * @return The focus color.
+   */
+  protected Color getFocusColor()
+  {
+    return focusColor;
+  }
+
+  /**
+   * Factory method to create a BasicSliderUI for the given {@link
+   * JComponent}, which should be a {@link JSlider}.
+   *
+   * @param b The {@link JComponent} a UI is being created for.
+   *
+   * @return A BasicSliderUI for the {@link JComponent}.
+   */
+  public static ComponentUI createUI(JComponent b)
+  {
+    return new BasicSliderUI((JSlider) b);
+  }
+
+  /**
+   * Installs and initializes all fields for this UI delegate. Any properties
+   * of the UI that need to be initialized and/or set to defaults will be
+   * done now. It will also install any listeners necessary.
+   *
+   * @param c The {@link JComponent} that is having this UI installed.
+   */
+  public void installUI(JComponent c)
+  {
+    super.installUI(c);
+    if (c instanceof JSlider)
+      {
+        slider = (JSlider) c;
+
+        focusRect = new Rectangle();
+        contentRect = new Rectangle();
+        thumbRect = new Rectangle();
+        trackRect = new Rectangle();
+        tickRect = new Rectangle();
+        labelRect = new Rectangle();
+
+        insetCache = slider.getInsets();
+        leftToRightCache = !slider.getInverted();
+
+        scrollTimer = new Timer();
+        scrollTimer.setDelay(200);
+        scrollTimer.setRepeats(true);
+
+        installDefaults(slider);
+        installListeners(slider);
+        installKeyboardActions(slider);
+	
+        calculateFocusRect();
+
+        calculateContentRect();
+        calculateThumbSize();
+        calculateTrackBuffer();
+        calculateTrackRect();
+        calculateThumbLocation();
+
+        calculateTickRect();
+        calculateLabelRect();	
+      }
+  }
+
+  /**
+   * Performs the opposite of installUI. Any properties or resources that need
+   * to be cleaned up will be done now. It will also uninstall any listeners
+   * it has. In addition, any properties of this UI will be nulled.
+   *
+   * @param c The {@link JComponent} that is having this UI uninstalled.
+   */
+  public void uninstallUI(JComponent c)
+  {
+    super.uninstallUI(c);
+
+    uninstallKeyboardActions(slider);
+    uninstallListeners(slider);
+
+    scrollTimer = null;
+
+    focusRect = null;
+    contentRect = null;
+    thumbRect = null;
+    trackRect = null;
+    tickRect = null;
+    labelRect = null;
+
+    focusInsets = null;
+  }
+
+  /**
+   * Initializes any default properties that this UI has from the
+   * defaults for the Basic look and feel.
+   *
+   * @param slider The {@link JSlider} that is having this UI installed.
+   */
+  protected void installDefaults(JSlider slider)
+  {
+    UIDefaults defaults = UIManager.getLookAndFeelDefaults();
+    
+    slider.setForeground(defaults.getColor("Slider.foreground"));
+    slider.setBackground(defaults.getColor("Slider.background"));
+    shadowColor = defaults.getColor("Slider.shadow");
+    highlightColor = defaults.getColor("Slider.highlight");
+    focusColor = defaults.getColor("Slider.focus");
+    slider.setBorder(defaults.getBorder("Slider.border"));
+    
+    thumbHeight = defaults.getInt("Slider.thumbHeight");
+    thumbWidth = defaults.getInt("Slider.thumbWidth");
+    tickHeight = defaults.getInt("Slider.tickHeight");
+    
+    focusInsets = defaults.getInsets("Slider.focusInsets");    
+  }
+
+  /**
+   * Creates a new {@link TrackListener}.
+   *
+   * @param slider The {@link JSlider} that this {@link TrackListener} is
+   *        created for.
+   *
+   * @return A new {@link TrackListener}.
+   */
+  protected TrackListener createTrackListener(JSlider slider)
+  {
+    return new TrackListener();
+  }
+
+  /**
+   * Creates a new {@link ChangeListener}.
+   *
+   * @param slider The {@link JSlider} that this {@link ChangeListener} is
+   *        created for.
+   *
+   * @return A new {@link ChangeListener}.
+   */
+  protected ChangeListener createChangeListener(JSlider slider)
+  {
+    return new ChangeHandler();
+  }
+
+  /**
+   * Creates a new {@link ComponentListener}.
+   *
+   * @param slider The {@link JSlider} that this {@link ComponentListener} is
+   *        created for.
+   *
+   * @return A new {@link ComponentListener}.
+   */
+  protected ComponentListener createComponentListener(JSlider slider)
+  {
+    return new ComponentHandler();
+  }
+
+  /**
+   * Creates a new {@link FocusListener}.
+   *
+   * @param slider The {@link JSlider} that this {@link FocusListener} is
+   *        created for.
+   *
+   * @return A new {@link FocusListener}.
+   */
+  protected FocusListener createFocusListener(JSlider slider)
+  {
+    return new FocusHandler();
+  }
+
+  /**
+   * Creates a new {@link ScrollListener}.
+   *
+   * @param slider The {@link JSlider} that this {@link ScrollListener} is
+   *        created for.
+   *
+   * @return A new {@link ScrollListener}.
+   */
+  protected ScrollListener createScrollListener(JSlider slider)
+  {
+    return new ScrollListener();
+  }
+
+  /**
+   * Creates a new {@link PropertyChangeListener}.
+   *
+   * @param slider The {@link JSlider} that this {@link
+   *        PropertyChangeListener} is created for.
+   *
+   * @return A new {@link PropertyChangeListener}.
+   */
+  protected PropertyChangeListener createPropertyChangeListener(JSlider slider)
+  {
+    return new PropertyChangeHandler();
+  }
+
+  /**
+   * Creates and registers all the listeners for this UI delegate. This
+   * includes creating the ScrollListener and registering it to the timer.
+   *
+   * @param slider The {@link JSlider} is having listeners installed.
+   */
+  protected void installListeners(JSlider slider)
+  {
+    propertyChangeListener = createPropertyChangeListener(slider);
+    componentListener = createComponentListener(slider);
+    trackListener = createTrackListener(slider);
+    focusListener = createFocusListener(slider);
+    changeListener = createChangeListener(slider);
+    scrollListener = createScrollListener(slider);
+
+    slider.addPropertyChangeListener(propertyChangeListener);
+    slider.addComponentListener(componentListener);
+    slider.addMouseListener(trackListener);
+    slider.addMouseMotionListener(trackListener);
+    slider.addFocusListener(focusListener);
+    slider.getModel().addChangeListener(changeListener);
+
+    scrollTimer.addActionListener(scrollListener);
+  }
+
+  /**
+   * Unregisters all the listeners that this UI delegate was using. In
+   * addition, it will also null any listeners that it was using.
+   *
+   * @param slider The {@link JSlider} that is having listeners removed.
+   */
+  protected void uninstallListeners(JSlider slider)
+  {
+    slider.removePropertyChangeListener(propertyChangeListener);
+    slider.removeComponentListener(componentListener);
+    slider.removeMouseListener(trackListener);
+    slider.removeMouseMotionListener(trackListener);
+    slider.removeFocusListener(focusListener);
+    slider.getModel().removeChangeListener(changeListener);
+
+    scrollTimer.removeActionListener(scrollListener);
+
+    propertyChangeListener = null;
+    componentListener = null;
+    trackListener = null;
+    focusListener = null;
+    changeListener = null;
+    scrollListener = null;
+  }
+
+  /**
+   * Installs any keyboard actions. The list of keys that need to be bound
+   * are listed in Basic look and feel's defaults.
+   *
+   * @param slider The {@link JSlider} that is having keyboard actions
+   *        installed.
+   */
+  protected void installKeyboardActions(JSlider slider)
+  {
+  }
+
+  /**
+   * Uninstalls any keyboard actions. The list of keys used  are listed in
+   * Basic look and feel's defaults.
+   *
+   * @param slider The {@link JSlider} that is having keyboard actions
+   *        uninstalled.
+   */
+  protected void uninstallKeyboardActions(JSlider slider)
+  {
+  }
+
+  /* XXX: This is all after experimentation with SUN's implementation.
+
+     PreferredHorizontalSize seems to be 200x21.
+     PreferredVerticalSize seems to be 21x200.
+
+     MinimumHorizontalSize seems to be 36x21.
+     MinimumVerticalSize seems to be 21x36.
+
+     PreferredSize seems to be 200x63. Or Components.getBounds?
+
+     MinimumSize seems to be 36x63.
+
+     MaximumSize seems to be 32767x63.
+   */
+
+  /**
+   * This method returns the preferred horizontal size. The vertical part of
+   * the dimension may be ignored.
+   *
+   * @return The dimensions of the preferred horizontal size.
+   */
+  public Dimension getPreferredHorizontalSize()
+  {
+    return new Dimension(200, thumbHeight + tickHeight);
+  }
+
+  /**
+   * This method returns the preferred vertical size. The horizontal part of
+   * the dimension may be ignored.
+   *
+   * @return The dimensions of the preferred vertical size.
+   */
+  public Dimension getPreferredVerticalSize()
+  {
+    return new Dimension(200, thumbHeight + tickHeight);
+  }
+
+  /**
+   * This method returns the minimum horizontal size. The vertical part of the
+   * dimension may be ignored.
+   *
+   * @return The dimensions of the minimum horizontal size.
+   */
+  public Dimension getMinimumHorizontalSize()
+  {
+    return new Dimension(4 * thumbWidth, thumbHeight);
+  }
+
+  /**
+   * This method returns the minimum vertical size. The horizontal part of the
+   * dimension may be ignored.
+   *
+   * @return The dimensions of the minimum vertical size.
+   */
+  public Dimension getMinimumVerticalSize()
+  {
+    return new Dimension(4 * thumbWidth, thumbHeight);
+  }
+
+  /**
+   * This method returns the preferred size of the component. If it returns
+   * null, then it is up to the Layout Manager to give the {@link JComponent}
+   * a size.
+   *
+   * @param c The {@link JComponent} to find the preferred size for.
+   *
+   * @return The dimensions of the preferred size.
+   */
+  public Dimension getPreferredSize(JComponent c)
+  {
+    return null;
+  }
+
+  /**
+   * This method returns the minimum size for this {@link JSlider}  for this
+   * look and feel. If it returns null, then it is up to the Layout Manager
+   * to give the {@link JComponent} a size.
+   *
+   * @param c The {@link JComponent} to find the minimum size for.
+   *
+   * @return The dimensions of the minimum size.
+   */
+  public Dimension getMinimumSize(JComponent c)
+  {
+    return null;
+  }
+
+  /**
+   * This method returns the maximum size for this {@link JSlider} for this
+   * look and feel. If it returns null, then it is up to the Layout Manager
+   * to give the {@link JComponent} a size.
+   *
+   * @param c The {@link JComponent} to find a maximum size for.
+   *
+   * @return The dimensions of the maximum size.
+   */
+  public Dimension getMaximumSize(JComponent c)
+  {
+    return null;
+  }
+
+  /**
+   * This method calculates the size and position of the
+   * <code>focusRect</code>. This method does not need to be called if the
+   * orientation changes.
+   */
+  protected void calculateFocusRect()
+  {
+    insetCache = slider.getInsets();
+    focusRect = SwingUtilities.calculateInnerArea(slider, focusRect);
+
+    focusRect.x = insetCache.left;
+    focusRect.y = insetCache.right;
+
+    if (focusRect.width < 0)
+      focusRect.width = 0;
+    if (focusRect.height < 0)
+      focusRect.height = 0;
+  }
+
+  /**
+   * This method calculates the size but not the position of the
+   * <code>thumbRect</code>. It must take into account the orientation of the
+   * slider.
+   */
+  protected void calculateThumbSize()
+  {
+    if (slider.getOrientation() == JSlider.HORIZONTAL)
+      {
+	if (thumbWidth > contentRect.width)
+	  thumbRect.width = contentRect.width / 4;
+	else
+	  thumbRect.width = thumbWidth;
+	if (thumbHeight > contentRect.height)
+	  thumbRect.height = contentRect.height;
+	else
+	  thumbRect.height = thumbHeight;
+      }
+    else
+      {
+	//The thumb gets flipped when inverted, so thumbWidth 
+	//actually is the height and vice versa.
+	if (thumbWidth > contentRect.height)
+	  thumbRect.height = contentRect.height / 4;
+	else
+	  thumbRect.height = thumbWidth;
+	if (thumbHeight > contentRect.width)
+	  thumbRect.width = contentRect.width;
+	else
+	  thumbRect.width = thumbHeight;
+      }
+  }
+
+  /**
+   * This method calculates the size and position of the
+   * <code>contentRect</code>. This method does not need to be  called if the
+   * orientation changes.
+   */
+  protected void calculateContentRect()
+  {
+    contentRect.x = focusRect.x + focusInsets.left;
+    contentRect.y = focusRect.y + focusInsets.top;
+    contentRect.width = focusRect.width - focusInsets.left - focusInsets.right;
+    contentRect.height = focusRect.height - focusInsets.top
+                         - focusInsets.bottom;
+
+    if (contentRect.width < 0)
+      contentRect.width = 0;
+    if (contentRect.height < 0)
+      contentRect.height = 0;
+  }
+
+  /**
+   * Calculates the position of the <code>thumbRect</code> based on the
+   * current value of the slider. It must take into  account the orientation
+   * of the slider.
+   */
+  protected void calculateThumbLocation()
+  {
+    int value = slider.getValue();
+
+    if (slider.getOrientation() == JSlider.HORIZONTAL)
+      {
+	thumbRect.x = xPositionForValue(value) - thumbRect.width / 2;
+	thumbRect.y = contentRect.y;
+      }
+    else
+      {
+	thumbRect.x = contentRect.x;
+	thumbRect.y = yPositionForValue(value) - thumbRect.height / 2;
+      }
+  }
+
+  /**
+   * Calculates the gap size between the left edge of the
+   * <code>contentRect</code> and the left edge of the
+   * <code>trackRect</code>.
+   */
+  protected void calculateTrackBuffer()
+  {
+    if (slider.getOrientation() == JSlider.HORIZONTAL)
+      trackBuffer = thumbRect.width;
+    else
+      trackBuffer = thumbRect.height;
+  }
+
+  /**
+   * This method returns the size of the <code>thumbRect</code>.
+   *
+   * @return The dimensions of the thumb.
+   */
+  protected Dimension getThumbSize()
+  {
+    // This is really just the bounds box for the thumb.
+    // The thumb will actually be pointed (like a rectangle + triangle at bottom)
+    return thumbRect.getSize();
+  }
+
+  /**
+   * Calculates the size and position of the <code>trackRect</code>. It must
+   * take into account the orientation of the slider.
+   */
+  protected void calculateTrackRect()
+  {
+    if (slider.getOrientation() == JSlider.HORIZONTAL)
+      {
+	trackRect.x = contentRect.x + trackBuffer;
+	trackRect.y = contentRect.y;
+	trackRect.width = contentRect.width - 2 * trackBuffer;
+	trackRect.height = thumbRect.height;
+      }
+    else
+      {
+	trackRect.x = contentRect.x;
+	trackRect.y = contentRect.y + trackBuffer;
+	trackRect.width = thumbRect.width;
+	trackRect.height = contentRect.height - 2 * trackBuffer;
+      }
+  }
+
+  /**
+   * This method returns the height of the tick area box if the slider  is
+   * horizontal and the width of the tick area box is the slider is vertical.
+   * It not necessarily how long the ticks will be. If a gap between the edge
+   * of tick box and the actual tick is desired, then that will need to be
+   * handled in the tick painting methods.
+   *
+   * @return The height (or width if the slider is vertical) of the tick
+   *         rectangle.
+   */
+  protected int getTickLength()
+  {
+    return tickHeight;
+  }
+
+  /**
+   * This method calculates the size and position of the
+   * <code>tickRect</code>. It must take into account the orientation of the
+   * slider.
+   */
+  protected void calculateTickRect()
+  {
+    if (slider.getOrientation() == JSlider.HORIZONTAL)
+      {
+	tickRect.x = trackRect.x;
+	tickRect.y = trackRect.y + trackRect.height;
+	tickRect.width = trackRect.width;
+	tickRect.height = getTickLength();
+
+	if (tickRect.y + tickRect.height > contentRect.y + contentRect.height)
+	  tickRect.height = contentRect.y + contentRect.height - tickRect.y;
+      }
+    else
+      {
+	tickRect.x = trackRect.x + trackRect.width;
+	tickRect.y = trackRect.y;
+	tickRect.width = getTickLength();
+	tickRect.height = trackRect.height;
+
+	if (tickRect.x + tickRect.width > contentRect.x + contentRect.width)
+	  tickRect.width = contentRect.x + contentRect.width - tickRect.x;
+      }
+  }
+
+  /**
+   * This method calculates the size and position of the
+   * <code>labelRect</code>. It must take into account the orientation of the
+   * slider.
+   */
+  protected void calculateLabelRect()
+  {
+    if (slider.getOrientation() == JSlider.HORIZONTAL)
+      {
+	labelRect.x = contentRect.x;
+	labelRect.y = tickRect.y + tickRect.height;
+	labelRect.width = contentRect.width;
+	labelRect.height = contentRect.height - labelRect.y;
+      }
+    else
+      {
+	labelRect.x = tickRect.x + tickRect.width;
+	labelRect.y = contentRect.y;
+	labelRect.width = contentRect.width - labelRect.x;
+	labelRect.height = contentRect.height;
+      }
+  }
+
+  /**
+   * This method returns the width of the widest label  in the slider's label
+   * table.
+   *
+   * @return The width of the widest label or 0 if no label table exists.
+   */
+  protected int getWidthOfWidestLabel()
+  {
+    int widest = 0;
+    Component label;
+
+    if (slider.getLabelTable() == null)
+      return 0;
+
+    for (Enumeration list = slider.getLabelTable().elements();
+         list.hasMoreElements();)
+      {
+        Object comp = list.nextElement();
+	if (!(comp instanceof Component))
+	  continue;
+	label = (Component) comp;
+	if (label.getWidth() > widest)
+	  widest = label.getWidth();
+      }
+    return widest;
+  }
+
+  /**
+   * This method returns the height of the tallest label in the slider's label
+   * table.
+   *
+   * @return The height of the tallest label or 0 if no label table exists.
+   */
+  protected int getHeightOfTallestLabel()
+  {
+    int tallest = 0;
+    Component label;
+
+    if (slider.getLabelTable() == null)
+      return 0;
+
+    for (Enumeration list = slider.getLabelTable().elements();
+         list.hasMoreElements();)
+      {
+        Object comp = list.nextElement();
+	if (!(comp instanceof Component))
+	  continue;
+	label = (Component) comp;
+	if (label.getHeight() > tallest)
+	  tallest = label.getHeight();
+      }
+    return tallest;
+  }
+
+  /**
+   * This method returns the width of the label whose key has the highest
+   * value.
+   *
+   * @return The width of the high value label or 0 if no label table exists.
+   */
+  protected int getWidthOfHighValueLabel()
+  {
+    Component highValueLabel = getHighestValueLabel();
+    if (highValueLabel != null)
+      return highValueLabel.getWidth();
+    else
+      return 0;
+  }
+
+  /**
+   * This method returns the width of the label whose key has the lowest
+   * value.
+   *
+   * @return The width of the low value label or 0 if no label table exists.
+   */
+  protected int getWidthOfLowValueLabel()
+  {
+    Component lowValueLabel = getLowestValueLabel();
+    if (lowValueLabel != null)
+      return lowValueLabel.getWidth();
+    else
+      return 0;
+  }
+
+  /**
+   * This method returns the height of the label whose key has the highest
+   * value.
+   *
+   * @return The height of the high value label or 0 if no label table exists.
+   */
+  protected int getHeightOfHighValueLabel()
+  {
+    Component highValueLabel = getHighestValueLabel();
+    if (highValueLabel != null)
+      return highValueLabel.getHeight();
+    else
+      return 0;
+  }
+
+  /**
+   * This method returns the height of the label whose key has the lowest
+   * value.
+   *
+   * @return The height of the low value label or 0 if no label table exists.
+   */
+  protected int getHeightOfLowValueLabel()
+  {
+    Component lowValueLabel = getLowestValueLabel();
+    if (lowValueLabel != null)
+      return lowValueLabel.getHeight();
+    else
+      return 0;
+  }
+
+  /**
+   * This method returns whether the slider is to be drawn inverted.
+   *
+   * @return True is the slider is to be drawn inverted.
+   */
+  protected boolean drawInverted()
+  {
+    return !leftToRightCache;
+  }
+
+  /**
+   * This method returns the label whose key has the lowest value.
+   *
+   * @return The low value label or null if no label table exists.
+   */
+  protected Component getLowestValueLabel()
+  {
+    Integer key = new Integer(Integer.MAX_VALUE);
+    Integer tmpKey;
+    Dictionary labelTable = slider.getLabelTable();
+
+    if (labelTable == null)
+      return null;
+
+    for (Enumeration list = labelTable.keys(); list.hasMoreElements();)
+      {
+        Object value = list.nextElement();
+	if (!(value instanceof Integer))
+	  continue;
+	tmpKey = (Integer) value;
+	if (tmpKey.intValue() < key.intValue())
+	  key = tmpKey;
+      }
+    Object comp = labelTable.get(key);
+    if (!(comp instanceof Component))
+      return null;
+    return (Component) comp;
+  }
+
+  /**
+   * This method returns the label whose  key has the highest value.
+   *
+   * @return The high value label or null if no label table exists.
+   */
+  protected Component getHighestValueLabel()
+  {
+    Integer key = new Integer(Integer.MIN_VALUE);
+    Integer tmpKey;
+    Dictionary labelTable = slider.getLabelTable();
+
+    if (labelTable == null)
+      return null;
+
+    for (Enumeration list = labelTable.keys(); list.hasMoreElements();)
+      {
+        Object value = list.nextElement();
+	if (!(value instanceof Integer))
+	  continue;
+	tmpKey = (Integer) value;
+	if (tmpKey.intValue() > key.intValue())
+	  key = tmpKey;
+      }
+    Object comp = labelTable.get(key);
+    if (!(comp instanceof Component))
+      return null;
+    return (Component) comp;
+  }
+
+  /**
+   * This method is used to paint the {@link JSlider}. It delegates all its
+   * duties to the various paint methods like paintTicks(),  paintTrack(),
+   * paintThumb(), etc.
+   *
+   * @param g The {@link Graphics} object to paint with.
+   * @param c The {@link JComponent} that is being painted.
+   */
+  public void paint(Graphics g, JComponent c)
+  {
+    //FIXME: Shouldn't have to call this here, but we don't seem to be getting any component
+    //resize events, so gotta stick with this for now.
+    calculateFocusRect();
+
+    calculateContentRect();
+    calculateThumbSize();
+    calculateTrackBuffer();
+    calculateTrackRect();
+    calculateThumbLocation();
+
+    calculateTickRect();
+    calculateLabelRect();
+
+    if (slider.getPaintTrack())
+      paintTrack(g);
+    if (slider.getPaintTicks())
+      paintTicks(g);
+    if (slider.getPaintLabels())
+      paintLabels(g);
+
+    //FIXME: Paint focus.
+    
+    paintThumb(g);
+  }
+
+  /**
+   * This method recalculates any rectangles that need to be recalculated
+   * after the insets of the component have changed.
+   */
+  protected void recalculateIfInsetsChanged()
+  {
+    //The focus rectangle needs to be calculated again and since
+    //the focus rectangle is an outer bounds for all other rectangles,
+    //they must be recalculated as well.
+    
+    //This method is able to calculate on component resize changes as well
+    //since the rectangles all need to be recalculated anyway.
+    calculateFocusRect();
+
+    calculateContentRect();
+    calculateThumbSize();
+    calculateTrackBuffer();
+    calculateTrackRect();
+    calculateThumbLocation();
+
+    calculateTickRect();
+    calculateLabelRect();
+  }
+
+  /**
+   * This method recalculates any rectangles that need to be recalculated
+   * after the orientation of the slider changes.
+   */
+  protected void recalculateIfOrientationChanged()
+  {
+    
+    calculateThumbSize();
+    calculateTrackBuffer();
+    calculateTrackRect();
+    calculateThumbLocation();
+
+    calculateTickRect();
+    calculateLabelRect();
+  }
+
+  /**
+   * This method is called during a repaint if the slider has focus. It draws
+   * an outline of the  <code>focusRect</code> using the color returned by
+   * getFocusColor().
+   *
+   * @param g The {@link Graphics} object to draw with.
+   */
+  public void paintFocus(Graphics g)
+  {
+    Color saved_color = g.getColor();
+
+    g.setColor(getFocusColor());
+
+    g.drawRect(focusRect.x, focusRect.y, focusRect.width, focusRect.height);
+
+    g.setColor(saved_color);
+  }
+
+  /**
+   * <p>
+   * This method is called during a repaint if the  track is to be drawn. It
+   * draws a 3D rectangle to  represent the track. The track is not the size
+   * of the <code>trackRect</code>. The top and left edges of the track should be outlined
+   * with the shadow color. The bottom and right edges should be outlined with
+   * the highlight color.
+   * </p>
+   *
+   * <pre>
+   *    a---d   
+   *    |   |   
+   *    |   |   a------------------------d
+   *    |   |   |                        |
+   *    |   |   b------------------------c
+   *    |   |
+   *    |   |   
+   *    b---c
+   * </pre>
+   * <p>
+   * The b-a-d path needs to be drawn with the shadow color and
+   * the b-c-d path needs to be drawn with the highlight color.
+   *
+   * @param g The {@link Graphics} object to draw with.
+   */
+  public void paintTrack(Graphics g)
+  {
+    Color saved_color = g.getColor();
+    int width;
+    int height;
+
+    Point a = new Point(trackRect.x, trackRect.y);
+    Point b = new Point(a);
+    Point c = new Point(a);
+    Point d = new Point(a);
+    
+    Polygon high, shadow;
+    
+    if (slider.getOrientation() == JSlider.HORIZONTAL)
+      {
+	width = trackRect.width;
+	height = (thumbRect.height / 4 == 0) ? 1 : thumbRect.height / 4;
+	
+	a.translate(0, (trackRect.height / 2) - (height / 2));
+	b.translate(0, (trackRect.height / 2) + (height / 2));
+	c.translate(trackRect.width, (trackRect.height / 2) + (height / 2));
+	d.translate(trackRect.width, (trackRect.height / 2) - (height / 2));		  
+      }
+    else
+      {
+	width = (thumbRect.width / 4 == 0) ? 1 : thumbRect.width / 4;
+	height = trackRect.height;
+	
+	a.translate((trackRect.width / 2) - (width / 2), 0);
+	b.translate((trackRect.width / 2) - (width / 2), trackRect.height);
+	c.translate((trackRect.width / 2) + (width / 2), trackRect.height);
+	d.translate((trackRect.width / 2) + (width / 2), 0);
+      }
+    high = new Polygon(new int[] {b.x, c.x, d.x},
+                       new int[] {b.y, c.y, d.y}, 3);
+    shadow = new Polygon(new int[] {b.x, a.x, d.x},
+                         new int[] {b.y, a.y, d.y}, 3);      
+			  
+    g.setColor(getHighlightColor());
+    g.drawPolygon(high);
+    g.setColor(getShadowColor());
+    g.drawPolygon(shadow);		
+	  
+    g.setColor(Color.GRAY);
+    g.fillRect(a.x + 1, a.y + 1, width - 2, height - 2);
+    g.setColor(saved_color);
+  }
+
+  /**
+   * This method is called during a repaint if the ticks are to be drawn. This
+   * method must still verify that the majorTickSpacing and minorTickSpacing
+   * are greater than zero before drawing the ticks.
+   *
+   * @param g The {@link Graphics} object to draw with.
+   */
+  public void paintTicks(Graphics g)
+  {
+    int max = slider.getMaximum();
+    int min = slider.getMinimum();
+    int majorSpace = slider.getMajorTickSpacing();
+    int minorSpace = slider.getMinorTickSpacing();
+
+    if (majorSpace > 0)
+      {
+	if (slider.getOrientation() == JSlider.HORIZONTAL)
+	  {
+	    int loc = tickRect.x;
+	    int increment = (max == min) ? 0
+	                                 : majorSpace * tickRect.width / (max
+	                                 - min);
+	    if (drawInverted())
+	      {
+		loc += tickRect.width;
+		increment *= -1;
+	      }
+	    for (int i = min; i <= max; i += majorSpace)
+	      {
+		paintMajorTickForHorizSlider(g, tickRect, loc);
+		loc += increment;
+	      }
+	  }
+	else
+	  {
+	    int loc = tickRect.height + tickRect.y;
+	    int increment = (max == min) ? 0
+	                                 : -majorSpace * tickRect.height / (max
+	                                 - min);
+	    if (drawInverted())
+	      {
+		loc = tickRect.y;
+		increment *= -1;
+	      }
+	    for (int i = min; i <= max; i += majorSpace)
+	      {
+		paintMajorTickForVertSlider(g, tickRect, loc);
+		loc += increment;
+	      }
+	  }
+      }
+    if (minorSpace > 0)
+      {
+	if (slider.getOrientation() == JSlider.HORIZONTAL)
+	  {
+	    int loc = tickRect.x;
+	    int increment = (max == min) ? 0
+	                                 : minorSpace * tickRect.width / (max
+	                                 - min);
+	    if (drawInverted())
+	      {
+		loc += tickRect.width;
+		increment *= -1;
+	      }
+	    for (int i = min; i <= max; i += minorSpace)
+	      {
+		paintMinorTickForHorizSlider(g, tickRect, loc);
+		loc += increment;
+	      }
+	  }
+	else
+	  {
+	    int loc = tickRect.height + tickRect.y;
+	    int increment = (max == min) ? 0
+	                                 : -minorSpace * tickRect.height / (max
+	                                 - min);
+	    if (drawInverted())
+	      {
+		loc = tickRect.y;
+		increment *= -1;
+	      }
+	    for (int i = min; i <= max; i += minorSpace)
+	      {
+		paintMinorTickForVertSlider(g, tickRect, loc);
+		loc += increment;
+	      }
+	  }
+      }
+  }
+
+  /* Minor ticks start at 1/4 of the height (or width) of the tickRect and extend
+     to 1/2 of the tickRect.
+
+     Major ticks start at 1/4 of the height and extend to 3/4.
+   */
+
+  /**
+   * This method paints a minor tick for a horizontal slider at the given
+   * <code>x</code> value. <code>x</code> represents the x coordinate to
+   * paint at.
+   *
+   * @param g The {@link Graphics} object to draw with.
+   * @param tickBounds The <code>tickRect</code> rectangle.
+   * @param x The x coordinate to draw the tick at.
+   */
+  protected void paintMinorTickForHorizSlider(Graphics g,
+                                              Rectangle tickBounds, int x)
+  {
+    int y = tickRect.y + tickRect.height / 4;
+
+    g.drawLine(x, y, x, y + tickRect.height / 4);
+  }
+
+  /**
+   * This method paints a major tick for a horizontal slider at the given
+   * <code>x</code> value. <code>x</code> represents the x coordinate to
+   * paint at.
+   *
+   * @param g The {@link Graphics} object to draw with.
+   * @param tickBounds The <code>tickRect</code> rectangle.
+   * @param x The x coordinate to draw the tick at.
+   */
+  protected void paintMajorTickForHorizSlider(Graphics g,
+                                              Rectangle tickBounds, int x)
+  {
+    int y = tickRect.y + tickRect.height / 4;
+
+    g.drawLine(x, y, x, y + tickRect.height / 2);
+  }
+
+  /**
+   * This method paints a minor tick for a vertical slider at the given
+   * <code>y</code> value. <code>y</code> represents the y coordinate to
+   * paint at.
+   *
+   * @param g The {@link Graphics} object to draw with.
+   * @param tickBounds The <code>tickRect</code> rectangle.
+   * @param y The y coordinate to draw the tick at.
+   */
+  protected void paintMinorTickForVertSlider(Graphics g, Rectangle tickBounds,
+                                             int y)
+  {
+    int x = tickRect.x + tickRect.width / 4;
+
+    g.drawLine(x, y, x + tickRect.width / 4, y);
+  }
+
+  /**
+   * This method paints a major tick for a vertical slider at the given
+   * <code>y</code> value. <code>y</code> represents the y coordinate to
+   * paint at.
+   *
+   * @param g The {@link Graphics} object to draw with.
+   * @param tickBounds The <code>tickRect</code> rectangle.
+   * @param y The y coordinate to draw the tick at.
+   */
+  protected void paintMajorTickForVertSlider(Graphics g, Rectangle tickBounds,
+                                             int y)
+  {
+    int x = tickRect.x + tickRect.width / 4;
+
+    g.drawLine(x, y, x + tickRect.width / 2, y);
+  }
+
+  /**
+   * This method paints all the labels from the slider's label table. This
+   * method must make sure that the label table is not null before painting
+   * the labels. Each entry in the label table is a (integer, component)
+   * pair. Every label is painted at the value of the integer.
+   *
+   * @param g The {@link Graphics} object to draw with.
+   */
+  public void paintLabels(Graphics g)
+  {
+    if (slider.getLabelTable() != null)
+      {
+      
+	Dictionary table = slider.getLabelTable();
+	Integer tmpKey;
+	Object key, element;
+	Component label;
+	if (slider.getOrientation() == JSlider.HORIZONTAL)
+	  {
+	    for (Enumeration list = table.keys(); list.hasMoreElements();)
+	      {
+                key = list.nextElement();
+		if (!(key instanceof Integer))
+		  continue;
+		tmpKey = (Integer) key;
+		element = table.get(tmpKey);
+		//We won't paint them if they're not
+		//JLabels so continue anyway
+		if (!(element instanceof JLabel))
+		  continue;
+		label = (Component) element;
+		paintHorizontalLabel(g, tmpKey.intValue(),
+		                     label);
+	      }
+	  }
+	else
+	  {
+	    for (Enumeration list = table.keys(); list.hasMoreElements();)
+	      {
+                key = list.nextElement();
+		if (!(key instanceof Integer))
+		  continue;
+		tmpKey = (Integer) key;
+		element = table.get(tmpKey);
+		//We won't paint them if they're not
+		//JLabels so continue anyway
+		if (!(element instanceof JLabel))
+		  continue;
+		label = (Component) element;
+		paintVerticalLabel(g, tmpKey.intValue(),
+		                   label);
+              }
+	  }
+      }
+  }
+
+  /**
+   * This method paints the label on the horizontal slider at the value
+   * specified. The value is not a coordinate. It is a value within the range
+   * of the  slider. If the value is not within the range of the slider,
+   * this method will do nothing. This method should not paint outside the
+   * boundaries of the <code>labelRect</code>.
+   *
+   * @param g The {@link Graphics} object to draw with.
+   * @param value The value to paint at.
+   * @param label The label to paint.
+   */
+  protected void paintHorizontalLabel(Graphics g, int value, Component label)
+  {
+    int w = label.getWidth();
+    int h = label.getHeight();
+
+    int max = slider.getMaximum();
+    int min = slider.getMinimum();
+
+    if (value > max || value < min)
+      return;
+
+    //FIXME: Shouldn't have to use w/2 here but it centers the label.
+    //Perhaps something in layoutCompoundLabel is broken.
+    //Observed same thing with ProgressBars.
+    int xpos = xPositionForValue(value) - w / 2;
+    int ypos = labelRect.y;
+
+    //We want to center the label around the xPositionForValue
+    //So we use xpos - w / 2. However, if value is min and the label 
+    //is large, we run the risk of going out of bounds. So we bring it back
+    //to 0 if it becomes negative.
+    if (xpos < 0)
+      xpos = 0;
+
+    //If the label + starting x position is greater than
+    //the x space in the label rectangle, we reset it to the largest
+    //amount possible in the rectangle. This means ugliness.
+    if (xpos + w > labelRect.x + labelRect.width)
+      w = labelRect.x + labelRect.width - xpos;
+
+    //If the label is too tall. We reset it to the height of the label
+    //rectangle.
+    if (h > labelRect.height)
+      h = labelRect.height;
+
+    label.setBounds(xpos, ypos, w, h);
+    javax.swing.SwingUtilities.paintComponent(g, label, null, label.getBounds());
+  }
+
+  /**
+   * This method paints the label on the vertical slider at the value
+   * specified. The value is not a coordinate. It is a value within the range
+   * of the  slider. If the value is not within the range of the slider,
+   * this method will do nothing. This method should not paint outside the
+   * boundaries of the <code>labelRect</code>.
+   *
+   * @param g The {@link Graphics} object to draw with.
+   * @param value The value to paint at.
+   * @param label The label to paint.
+   */
+  protected void paintVerticalLabel(Graphics g, int value, Component label)
+  {
+    int w = label.getWidth();
+    int h = label.getHeight();
+
+    int max = slider.getMaximum();
+    int min = slider.getMinimum();
+
+    if (value > max || value < min)
+      return;
+
+    int xpos = labelRect.x;
+
+    //FIXME: Shouldn't have to use h/2 here but it centers the label.
+    //Perhaps something in layoutCompoundLabel is broken.
+    //Observed same thing with ProgressBars.    
+    int ypos = yPositionForValue(value) - h / 2;
+
+    if (ypos < 0)
+      ypos = 0;
+
+    if (ypos + h > labelRect.y + labelRect.height)
+      h = labelRect.y + labelRect.height - ypos;
+
+    if (w > labelRect.width)
+      w = labelRect.width;
+
+    label.setBounds(xpos, ypos, w, h);
+    javax.swing.SwingUtilities.paintComponent(g, label, null, label.getBounds());
+  }
+
+  /**
+   * <p>
+   * This method paints a thumb. There are two types of thumb:
+   * </p>
+   * <pre>
+   *   Vertical         Horizontal
+   *    a---b            a-----b
+   *    |   |            |      \
+   *    e   c            |       c
+   *     \ /             |      /
+   *      d              e-----d
+   *  </pre>
+   * 
+   * <p>
+   * In the case of vertical thumbs, we highlight the path b-a-e-d and shadow
+   * the path b-c-d. In the case of horizontal thumbs, we highlight the path
+   * c-b-a-e and shadow the path c-d-e. In both cases we fill the path
+   * a-b-c-d-e before shadows and highlights are drawn.
+   * </p>
+   *
+   * @param g The graphics object to paint with
+   */
+  public void paintThumb(Graphics g)
+  {
+    Color saved_color = g.getColor();
+
+    Polygon thumb = new Polygon();
+
+    Point a = new Point(thumbRect.x, thumbRect.y);
+    Point b = new Point(a);
+    Point c = new Point(a);
+    Point d = new Point(a);
+    Point e = new Point(a);
+
+    Polygon bright;
+    Polygon dark;
+    Polygon all;
+
+    //This will be in X-dimension if the slider is inverted and y if it isn't.	  	  
+    int turnPoint;
+
+    if (slider.getOrientation() == JSlider.HORIZONTAL)
+      {
+	turnPoint = thumbRect.height * 3 / 4;
+
+	b.translate(thumbRect.width, 0);
+	c.translate(thumbRect.width, turnPoint);
+	d.translate(thumbRect.width / 2, thumbRect.height);
+	e.translate(0, turnPoint);
+
+	bright = new Polygon(new int[] { b.x, a.x, e.x, d.x },
+	                     new int[] { b.y, a.y, e.y, d.y }, 4);
+
+	dark = new Polygon(new int[] { b.x, c.x, d.x },
+	                   new int[] { b.y, c.y, d.y }, 3);
+        all = new Polygon(new int[] { a.x + 1, b.x, c.x, d.x, e.x + 1},
+                 new int[] { a.y + 1, b.y + 1, c.y, d.y + 1, e.y }, 5);			   
+      }
+    else
+      {
+	turnPoint = thumbRect.width * 3 / 4;
+
+	b.translate(turnPoint, 0);
+	c.translate(thumbRect.width, thumbRect.height / 2);
+	d.translate(turnPoint, thumbRect.height);
+	e.translate(0, thumbRect.height);
+
+	bright = new Polygon(new int[] { c.x, b.x, a.x, e.x },
+	                     new int[] { c.y, b.y, a.y, e.y }, 4);
+
+	dark = new Polygon(new int[] { c.x, d.x, e.x + 1 },
+	                   new int[] { c.y, d.y, e.y }, 3);
+
+        all = new Polygon(new int[] { a.x + 1, b.x, c.x - 1, d.x, e.x + 1 },
+	                  new int[] { a.y + 1, b.y + 1, c.y, d.y, e.y}, 5);			   
+      }
+
+
+    g.setColor(Color.WHITE);
+    g.drawPolygon(bright);
+
+    g.setColor(Color.BLACK);
+    g.drawPolygon(dark);
+
+    g.setColor(Color.GRAY);
+    g.fillPolygon(all);
+
+    g.setColor(saved_color);
+  }
+
+  /**
+   * This method sets the position of the <code>thumbRect</code>.
+   *
+   * @param x The new x position.
+   * @param y The new y position.
+   */
+  public void setThumbLocation(int x, int y)
+  {
+    thumbRect.x = x;
+    thumbRect.y = y;
+  }
+
+  /**
+   * This method is used to move the thumb one  block in the direction
+   * specified. If the slider  snaps to ticks, this method is responsible for
+   * snapping it to a tick after the thumb  has been moved.
+   *
+   * @param direction The direction to move in.
+   */
+  public void scrollByBlock(int direction)
+  {
+    //The direction is -1 for backwards and 1 for forwards.
+    int unit = direction * (slider.getMaximum() - slider.getMinimum()) / 10;
+
+    int moveTo = slider.getValue() + unit;
+
+    if (slider.getSnapToTicks())
+      moveTo = findClosestTick(moveTo);
+
+    slider.setValue(moveTo);
+  }
+
+  /**
+   * This method is used to move the thumb one unit in the direction
+   * specified. If the slider snaps to ticks, this method is responsible for
+   * snapping it to a tick after the thumb has been moved.
+   *
+   * @param direction The direction to move in.
+   */
+  public void scrollByUnit(int direction)
+  {
+    //The direction is -1 for backwards and 1 for forwards.
+    int moveTo = slider.getValue() + direction;
+
+    if (slider.getSnapToTicks())
+      moveTo = findClosestTick(moveTo);
+
+    slider.setValue(moveTo);
+  }
+
+  /**
+   * This method is called when there has been a click in the track and the
+   * thumb needs to be scrolled  on regular intervals. This method is only
+   * responsible  for starting the timer and not for stopping it.
+   *
+   * @param dir The direction to move in.
+   */
+  protected void scrollDueToClickInTrack(int dir)
+  {
+    scrollListener.setDirection(dir);
+    scrollListener.setScrollByBlock(true);
+
+    scrollTimer.start();
+  }
+
+  /**
+   * This method returns the X coordinate for the value passed in.
+   *
+   * @param value The value to calculate an x coordinate for.
+   *
+   * @return The x coordinate for the value.
+   */
+  protected int xPositionForValue(int value)
+  {
+    int min = slider.getMinimum();
+    int max = slider.getMaximum();
+    int extent = slider.getExtent();
+    int len = trackRect.width;
+
+    int xPos = (max == min) ? 0 : (value - min) * len / (max - min);
+
+    if (! drawInverted())
+      xPos += trackRect.x;
+    else
+      {
+	xPos = trackRect.width - xPos;
+	xPos += trackRect.x;
+      }
+    return xPos;
+  }
+
+  /**
+   * This method returns the y coordinate for the value passed in.
+   *
+   * @param value The value to calculate a y coordinate for.
+   *
+   * @return The y coordinate for the value.
+   */
+  protected int yPositionForValue(int value)
+  {
+    int min = slider.getMinimum();
+    int max = slider.getMaximum();
+    int extent = slider.getExtent();
+    int len = trackRect.height;
+
+    int yPos = (max == min) ? 0 : (value - min) * len / (max - min);
+
+    if (! drawInverted())
+      {
+	yPos = trackRect.height - yPos;
+	yPos += trackRect.y;
+      }
+    else
+      yPos += trackRect.y;
+    return yPos;
+  }
+
+  /**
+   * This method returns the value in the slider's range given the y
+   * coordinate. If the value is out of range, it will  return the closest
+   * legal value.
+   *
+   * @param yPos The y coordinate to calculate a value for.
+   *
+   * @return The value for the y coordinate.
+   */
+  public int valueForYPosition(int yPos)
+  {
+    int min = slider.getMinimum();
+    int max = slider.getMaximum();
+    int len = trackRect.height;
+
+    int value;
+
+    //If the length is 0, you shouldn't be able to even see where the slider is.
+    //This really shouldn't ever happen, but just in case, we'll return the middle.
+    if (len == 0)
+      return ((max - min) / 2);
+
+    if (! drawInverted())
+      value = ((len - (yPos - trackRect.y)) * (max - min) / len + min);
+    else
+      value = ((yPos - trackRect.y) * (max - min) / len + min);
+    
+    //If this isn't a legal value, then we'll have to move to one now.
+    if (value > max)
+      value = max;
+    else if (value < min)
+      value = min;
+    return value;
+  }
+
+  /**
+   * This method returns the value in the slider's range given the x
+   * coordinate. If the value is out of range, it will return the closest
+   * legal value.
+   *
+   * @param xPos The x coordinate to calculate a value for.
+   *
+   * @return The value for the x coordinate.
+   */
+  public int valueForXPosition(int xPos)
+  {
+    int min = slider.getMinimum();
+    int max = slider.getMaximum();
+    int len = trackRect.width;
+
+    int value;
+
+    //If the length is 0, you shouldn't be able to even see where the slider is.
+    //This really shouldn't ever happen, but just in case, we'll return the middle.
+    if (len == 0)
+      return ((max - min) / 2);
+
+    if (! drawInverted())
+      value = ((xPos - trackRect.x) * (max - min) / len + min);
+    else
+      value = ((len - (xPos - trackRect.x)) * (max - min) / len + min);
+    
+    //If this isn't a legal value, then we'll have to move to one now.
+    if (value > max)
+      value = max;
+    else if (value < min)
+      value = min;
+    return value;
+  }
+
+  /**
+   * This method finds the closest value that has a tick associated with it.
+   *
+   * @param value The value to search from.
+   *
+   * @return The closest value that has a tick associated with it.
+   */
+  private int findClosestTick(int value)
+  {
+    int min = slider.getMinimum();
+    int max = slider.getMaximum();
+    int majorSpace = slider.getMajorTickSpacing();
+    int minorSpace = slider.getMinorTickSpacing();
+
+    //The default value to return is value + minor or
+    //value + major. 
+    //Initializing at min - value leaves us with a default
+    //return value of min, which always has tick marks
+    //(if ticks are painted).
+    int minor = min - value;
+    int major = min - value;
+    
+    //If there are no major tick marks or minor tick marks 
+    //e.g. snap is set to true but no ticks are set, then
+    //we can just return the value.
+    if (majorSpace <= 0 && minorSpace <= 0)
+      return value;
+
+    //First check the major ticks.
+    if (majorSpace > 0)
+      {
+	int lowerBound = (value - min) / majorSpace;
+	int majLower = majorSpace * lowerBound + min;
+	int majHigher = majorSpace * (lowerBound + 1) + min;
+
+	if (majHigher <= max && majHigher - value <= value - majLower)
+	  major = majHigher - value;
+	else
+	  major = majLower - value;
+      }
+
+    if (minorSpace > 0)
+      {
+	int lowerBound = value / minorSpace;
+	int minLower = minorSpace * lowerBound;
+	int minHigher = minorSpace * (lowerBound + 1);
+
+	if (minHigher <= max && minHigher - value <= value - minLower)
+	  minor = minHigher - value;
+	else
+	  minor = minLower - value;
+      }
+
+    //Give preference to minor ticks
+    if (Math.abs(minor) > Math.abs(major))
+      return value + major;
+    else
+      return value + minor;
+  }
+}

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]