[llvm-commits] [llvm-gcc-4.2] r43913 [52/80] - in /llvm-gcc-4.2/trunk: boehm-gc/ boehm-gc/Mac_files/ boehm-gc/cord/ boehm-gc/doc/ boehm-gc/include/ boehm-gc/include/private/ boehm-gc/tests/ libffi/ libffi/include/ libffi/src/ libffi/src/alpha/ libffi/src/arm/ libffi/src/cris/ libffi/src/frv/ libffi/src/ia64/ libffi/src/m32r/ libffi/src/m68k/ libffi/src/mips/ libffi/src/pa/ libffi/src/powerpc/ libffi/src/s390/ libffi/src/sh/ libffi/src/sh64/ libffi/src/sparc/ libffi/src/x86/ libffi/testsuite/ libffi/testsuite/config/ li...

Bill Wendling isanbard at gmail.com
Thu Nov 8 14:57:11 PST 2007


Added: llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/BasicProgressBarUI.java
URL: http://llvm.org/viewvc/llvm-project/llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/BasicProgressBarUI.java?rev=43913&view=auto

==============================================================================
--- llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/BasicProgressBarUI.java (added)
+++ llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/BasicProgressBarUI.java Thu Nov  8 16:56:19 2007
@@ -0,0 +1,948 @@
+/* BasicProgressBarUI.java --
+   Copyright (C) 2004, 2005  Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package javax.swing.plaf.basic;
+
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.Font;
+import java.awt.FontMetrics;
+import java.awt.Graphics;
+import java.awt.Insets;
+import java.awt.Point;
+import java.awt.Rectangle;
+import java.awt.Shape;
+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.geom.AffineTransform;
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+
+import javax.swing.JComponent;
+import javax.swing.JProgressBar;
+import javax.swing.LookAndFeel;
+import javax.swing.SwingConstants;
+import javax.swing.SwingUtilities;
+import javax.swing.Timer;
+import javax.swing.UIManager;
+import javax.swing.event.AncestorEvent;
+import javax.swing.event.AncestorListener;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+import javax.swing.plaf.ComponentUI;
+import javax.swing.plaf.ProgressBarUI;
+
+/**
+ * The Basic Look and Feel UI delegate for the 
+ * JProgressBar.
+ */
+public class BasicProgressBarUI extends ProgressBarUI
+{
+  /**
+   * A helper class that listens for ChangeEvents 
+   * from the progressBar's model.
+   *
+   * @specnote Apparently this class was intended to be protected,
+   *           but was made public by a compiler bug and is now
+   *           public for compatibility.
+   */
+  public class ChangeHandler implements ChangeListener
+  {
+    /**
+     * Called every time the state of the model changes.
+     *
+     * @param e The ChangeEvent given by the model.
+     */
+    public void stateChanged(ChangeEvent e)
+    {
+      // Nothing to do but repaint.
+      progressBar.repaint();
+    }
+  }
+
+  /**
+   * This helper class is used to listen for 
+   * PropertyChangeEvents from the progressBar.
+   */
+  private class PropertyChangeHandler implements PropertyChangeListener
+  {
+    /**
+     * Called every time the properties of the 
+     * progressBar change.
+     *
+     * @param e The PropertyChangeEvent given by the progressBar.
+     */
+    public void propertyChange(PropertyChangeEvent e)
+    {
+      // Only need to listen for indeterminate changes.
+      // All other things are done on a repaint.
+      if (e.getPropertyName().equals("indeterminate"))
+        if (((Boolean) e.getNewValue()).booleanValue()
+            && progressBar.isShowing())
+          startAnimationTimer();
+        else
+          stopAnimationTimer();
+    }
+  }
+
+  /**
+   * Receives notification when the progressbar is becoming visible or
+   * invisible and starts/stops the animation timer accordingly.
+   *
+   * @author Roman Kennke (kennke at aicas.com)
+   */
+  private class AncestorHandler implements AncestorListener
+  {
+
+    /**
+     * Receives notification when the progressbar is becoming visible. This
+     * starts the animation timer if the progressbar is indeterminate.
+     *
+     * @param event the ancestor event
+     */
+    public void ancestorAdded(AncestorEvent event)
+    {
+      if (progressBar.isIndeterminate())
+        startAnimationTimer();
+    }
+
+    /**
+     * Receives notification when the progressbar is becoming invisible. This
+     * stops the animation timer if the progressbar is indeterminate.
+     *
+     * @param event the ancestor event
+     */
+    public void ancestorRemoved(AncestorEvent event)
+    {
+      stopAnimationTimer();
+    }
+
+    /**
+     * Receives notification when an ancestor has been moved. We don't need to
+     * do anything here.
+     */
+    public void ancestorMoved(AncestorEvent event)
+    {
+      // Nothing to do here.
+    }
+    
+  }
+
+  /**
+   * This helper class is used to listen for 
+   * the animationTimer's intervals. On every interval,
+   * the bouncing box should move.
+   */
+  private class Animator implements ActionListener
+  {
+    /**
+     * Called every time the animationTimer reaches
+     * its interval.
+     *
+     * @param e The ActionEvent given by the timer.
+     */
+    public void actionPerformed(ActionEvent e)
+    {
+      // Incrementing the animation index will cause
+      // a repaint.
+      incrementAnimationIndex();
+    }
+  }
+
+  /**
+   * Receives notification when the size of the progress bar changes and
+   * invalidates the layout information for the box calculation in
+   * {@link BasicProgressBarUI#getBox(Rectangle)}.
+   *
+   * @author Roman Kennke (kennke at aicas.com)
+   */
+  private class ComponentHandler extends ComponentAdapter
+  {
+    /**
+     * Receives notification when the size of the progress bar changes and
+     * invalidates the layout information for the box calculation in
+     * {@link BasicProgressBarUI#getBox}.
+     *
+     * @param e the component event
+     */
+    public void componentResized(ComponentEvent e)
+    {
+      boxDependent = -1;
+      boxIndependent = -1;
+      incr = -1;
+    }
+  }
+
+  /**
+   * Holds the value of the bouncing box that is returned by {@link #getBox}.
+   *
+   * @since 1.5
+   */ 
+  protected Rectangle boxRect;
+
+  /** The timer used to move the bouncing box. */
+  private transient Timer animationTimer;
+
+  // The total number of frames must be an even number.
+  // The total number of frames is calculated from
+  // the cycleTime and repaintInterval given by
+  // the basic Look and Feel defaults.
+  //
+  // +-----------------------------------------------+
+  // | frame0 | frame1 | frame2 | frame 3 | frame 4  |
+  // |        | frame7 | frame6 | frame 5 |          |
+  // +-----------------------------------------------+
+  
+  /** The current animation index. */
+  private transient int animationIndex;
+
+  /** The total number of frames.*/
+  private transient int numFrames;
+
+  /** The helper that moves the bouncing box. */
+  private transient Animator animation;
+
+  /** The helper that listens for property change events. */
+  private transient PropertyChangeHandler propertyListener;
+
+  /** The Listener for the model. */
+  protected ChangeListener changeListener;
+
+  /** The progressBar for this UI. */
+  protected JProgressBar progressBar;
+
+
+  /**
+   * The size of the box returned by {@link #getBox} in the orientation
+   * direction of the progress bar. This is package private to avoid accessor
+   * method.
+   */
+  transient double boxDependent = - 1;
+
+  /**
+   * The size of the box returned by {@link #getBox} against the orientation
+   * direction of the progress bar. This is package private to avoid accessor
+   * method. 
+   */
+  transient int boxIndependent = - 1;
+
+  /**
+   * The increment for box animation. This is package private to avoid accessor
+   * method.
+   */
+  transient double incr = -1;
+
+  /** The length of the cell. The cell is the painted part. */
+  private transient int cellLength;
+
+  /** The gap between cells. */
+  private transient int cellSpacing;
+
+  /** The color of the text when the bar is not over it.*/
+  private transient Color selectionBackground;
+
+  /** The color of the text when the bar is over it. */
+  private transient Color selectionForeground;
+
+  /**
+   * Listens for notification when the component becomes showing and
+   * starts/stops the animation timer.
+   */
+  private AncestorListener ancestorListener;
+
+  /**
+   * Listens for resize events on the progress bar and invalidates some
+   * layout info.
+   */
+  private ComponentListener componentListener;
+
+  /**
+   * Creates a new BasicProgressBarUI object.
+   */
+  public BasicProgressBarUI()
+  {
+    super();
+  }
+
+  /**
+   * Creates a new BasicProgressBarUI for the component.
+   *
+   * @param x The JComponent to create the UI for.
+   *
+   * @return A new BasicProgressBarUI.
+   */
+  public static ComponentUI createUI(JComponent x)
+  {
+    return new BasicProgressBarUI();
+  }
+
+  /**
+   * This method returns the length of the bar (from the minimum)
+   * in pixels (or units that the Graphics object draws in) based
+   * on the progressBar's getPercentComplete() value.
+   *
+   * @param b The insets of the progressBar.
+   * @param width The width of the progressBar.
+   * @param height The height of the progressBar.
+   *
+   * @return The length of the bar that should be painted in pixels.
+   */
+  protected int getAmountFull(Insets b, int width, int height)
+  {
+    double percentDone = progressBar.getPercentComplete();
+    if (progressBar.getOrientation() == JProgressBar.HORIZONTAL)
+      return (int) (percentDone * (width - b.left - b.right));
+    else
+      return (int) (percentDone * (height - b.top - b.bottom));
+  }
+
+  /**
+   * The current animation index.
+   *
+   * @return The current animation index.
+   */
+  protected int getAnimationIndex()
+  {
+    return animationIndex;
+  }
+
+  /**
+   * This method returns the size and position of the bouncing box
+   * for the current animation index. It stores the values in the 
+   * given rectangle and returns it. It returns null if no box should
+   * be drawn.
+   *
+   * @param r The bouncing box rectangle.
+   *
+   * @return The bouncing box rectangle.
+   */
+  protected Rectangle getBox(Rectangle r)
+  {
+    if (!progressBar.isIndeterminate())
+      return null;
+    if (r == null)
+      r = new Rectangle();
+
+    Rectangle vr = new Rectangle();
+    SwingUtilities.calculateInnerArea(progressBar, vr);
+
+    // Recalculate the metrics only when size of the progressbar has changed.
+    if (incr == -1 || boxDependent == -1 || boxIndependent == -1)
+      {
+        //numFrames has to be an even number as defined by spec.
+        int iterations = numFrames / 2;
+        if (progressBar.getOrientation() == JProgressBar.HORIZONTAL)
+          {
+            boxDependent = vr.width / 6.;
+            incr = ((double) (vr.width - boxDependent)) / (double) iterations;
+            boxIndependent = vr.height;
+          }
+        else
+          {
+            boxDependent = vr.height / 6.;
+            incr = ((double) (vr.height - boxDependent)) / (double) iterations;
+            boxIndependent = vr.width;
+          }
+      }
+
+    int index = getAnimationIndex();
+    if (animationIndex > numFrames / 2)
+      index = numFrames - getAnimationIndex();
+
+    if (progressBar.getOrientation() == JProgressBar.HORIZONTAL)
+      {
+        r.x = vr.x + (int) (incr * index);
+        r.y = vr.y;
+        r.width = (int) boxDependent;
+        r.height = (int) boxIndependent;
+      }
+    else
+      {
+        r.x = vr.x;
+        r.y = vr.height - (int) (incr * index) + vr.y - (int) boxDependent;
+        r.width = (int) boxIndependent;
+        r.height = (int) boxDependent;
+      }
+    return r;
+  }
+
+  /**
+   * This method returns the length of the cells.
+   *
+   * @return The cell length.
+   */
+  protected int getCellLength()
+  {
+    return cellLength;
+  }
+
+  /**
+   * This method returns the spacing between cells.
+   *
+   * @return The cell gap.
+   */
+  protected int getCellSpacing()
+  {
+    return cellSpacing;
+  }
+
+  /**
+   * This method returns the maximum size of the JComponent.
+   * If it returns null, it is up to the LayoutManager
+   * to give it a size.
+   *
+   * @param c The component to find a maximum size for.
+   *
+   * @return The maximum size.
+   */
+  public Dimension getMaximumSize(JComponent c)
+  {
+    Insets insets = c.getInsets();
+    Dimension ret;
+    int orientation = progressBar.getOrientation();
+    if (orientation == JProgressBar.VERTICAL)
+      {
+        ret = getPreferredInnerVertical();
+        ret.height = Short.MAX_VALUE;
+        ret.width += insets.left + insets.right;
+      }
+    else
+      {
+        ret = getPreferredInnerHorizontal();
+        ret.width = Short.MAX_VALUE;
+        ret.height += insets.top + insets.bottom;
+      }
+    return ret;
+  }
+
+  /**
+   * This method returns the minimum size of the JComponent.
+   * If it returns null, it is up to the LayoutManager to
+   * give it a size.
+   *
+   * @param c The component to find a minimum size for.
+   *
+   * @return The minimum size.
+   */
+  public Dimension getMinimumSize(JComponent c)
+  {
+    Insets insets = c.getInsets();
+    Dimension ret;
+    int orientation = progressBar.getOrientation();
+    if (orientation == JProgressBar.VERTICAL)
+      {
+        ret = getPreferredInnerVertical();
+        ret.height = 10;
+        ret.width += insets.left + insets.right;
+      }
+    else
+      {
+        ret = getPreferredInnerHorizontal();
+        ret.width = 10;
+        ret.height += insets.top + insets.bottom;
+      }
+    return ret;
+  }
+
+  /**
+   * This method returns the preferred size of the inner
+   * rectangle (the bounds without the insets) if the
+   * progressBar is horizontal.
+   *
+   * @return The preferred size of the progressBar minus 
+   *         insets if it's horizontal.
+   */
+  protected Dimension getPreferredInnerHorizontal()
+  {
+    Font font = progressBar.getFont();
+    FontMetrics fm = progressBar.getFontMetrics(font);
+
+    int stringWidth = 0;
+    String str = progressBar.getString();
+    if (str != null)
+      stringWidth = fm.stringWidth(progressBar.getString());
+    Insets i = progressBar.getInsets();
+    int prefWidth = Math.max(200 - i.left - i.right, stringWidth);
+
+    int stringHeight = 0;
+    if (str != null)
+      stringHeight = fm.getHeight();
+    int prefHeight = Math.max(16 - i.top - i.bottom, stringHeight);
+
+    return new Dimension(prefWidth, prefHeight);
+  }
+
+  /**
+   * This method returns the preferred size of the inner
+   * rectangle (the bounds without insets) if the 
+   * progressBar is vertical.
+   *
+   * @return The preferred size of the progressBar minus
+   *         insets if it's vertical.
+   */
+  protected Dimension getPreferredInnerVertical()
+  {
+    Font font = progressBar.getFont();
+    FontMetrics fm = progressBar.getFontMetrics(font);
+
+    int stringWidth = 0;
+    String str = progressBar.getString();
+    if (str != null)
+      stringWidth = fm.stringWidth(progressBar.getString());
+    Insets i = progressBar.getInsets();
+    int prefHeight = Math.max(200 - i.left - i.right, stringWidth);
+
+    int stringHeight = 0;
+    if (str != null)
+      stringHeight = fm.getHeight();
+    int prefWidth = Math.max(16 - i.top - i.bottom, stringHeight);
+
+    return new Dimension(prefWidth, prefHeight);
+  }
+
+  /**
+   * This method returns the preferred size of the 
+   * given JComponent. If it returns null, then it
+   * is up to the LayoutManager to give it a size.
+   *
+   * @param c The component to find the preferred size for.
+   *
+   * @return The preferred size of the component.
+   */
+  public Dimension getPreferredSize(JComponent c)
+  {
+    Insets insets = c.getInsets();
+    Dimension ret;
+    int orientation = progressBar.getOrientation();
+    if (orientation == JProgressBar.VERTICAL)
+      ret = getPreferredInnerVertical();
+    else
+      ret = getPreferredInnerHorizontal();
+    ret.width += insets.left + insets.right;
+    ret.height += insets.top + insets.bottom;
+    return ret;
+  }
+
+  /**
+   * This method returns the Color that the text is shown in when the bar is
+   * not over the text.
+   *
+   * @return The color of the text when the bar is not over it.
+   */
+  protected Color getSelectionBackground()
+  {
+    return selectionBackground;
+  }
+
+  /**
+   * This method returns the Color that the text is shown in  when the bar is
+   * over the text.
+   *
+   * @return The color of the text when the bar is over it.
+   */
+  protected Color getSelectionForeground()
+  {
+    return selectionForeground;
+  }
+
+  /**
+   * This method returns the point (the top left of the bounding box)
+   * where the text should be painted. 
+   *
+   * @param g The Graphics object to measure FontMetrics with.
+   * @param progressString The string to paint.
+   * @param x The x coordinate of the overall bounds box.
+   * @param y The y coordinate of the overall bounds box.
+   * @param width The width of the overall bounds box.
+   * @param height The height of the overall bounds box.
+   *
+   * @return The top left of the bounding box where text should be painted.
+   */
+  protected Point getStringPlacement(Graphics g, String progressString, int x,
+                                     int y, int width, int height)
+  {
+    Rectangle tr = new Rectangle();
+    Rectangle vr = new Rectangle(x, y, width, height);
+    Rectangle ir = new Rectangle();
+
+    Font f = g.getFont();
+    FontMetrics fm = g.getFontMetrics(f);
+
+    SwingUtilities.layoutCompoundLabel(progressBar, fm, progressString, null,
+                                       SwingConstants.CENTER,
+                                       SwingConstants.CENTER,
+                                       SwingConstants.CENTER,
+                                       SwingConstants.CENTER, vr, ir, tr, 0);
+    return new Point(tr.x, tr.y);
+  }
+
+  /**
+   * This method increments the animation index.
+   */
+  protected void incrementAnimationIndex()
+  {
+    animationIndex++;
+    //numFrames is like string length, it should be named numFrames or something
+    if (animationIndex >= numFrames)
+      animationIndex = 0;
+    progressBar.repaint();
+  }
+
+  /**
+   * This method paints the progressBar. It delegates its responsibilities
+   * to paintDeterminate and paintIndeterminate.
+   *
+   * @param g The Graphics object to paint with.
+   * @param c The JComponent to paint.
+   */
+  public void paint(Graphics g, JComponent c)
+  {
+    if (! progressBar.isIndeterminate())
+      paintDeterminate(g, c);
+    else
+      paintIndeterminate(g, c);
+  }
+
+  /**
+   * This method is called if the painting to be done is 
+   * for a determinate progressBar.
+   *
+   * @param g The Graphics object to paint with.
+   * @param c The JComponent to paint.
+   */
+  protected void paintDeterminate(Graphics g, JComponent c)
+  {
+    Color saved = g.getColor();
+    int space = getCellSpacing();
+    int len = getCellLength();
+    int max = progressBar.getMaximum();
+    int min = progressBar.getMinimum();
+    int value = progressBar.getValue();
+
+    Rectangle vr = SwingUtilities.calculateInnerArea(c, new Rectangle());
+    Rectangle or = progressBar.getBounds();
+    Insets insets = c.getInsets();
+
+    int amountFull = getAmountFull(insets, or.width, or.height);
+
+	if (progressBar.getOrientation() == JProgressBar.HORIZONTAL)
+	  {
+	    g.setColor(c.getForeground());
+	    g.fillRect(vr.x, vr.y, amountFull, vr.height);
+	  }
+	else
+	  {
+	    g.setColor(c.getForeground());
+	    g.fillRect(vr.x, vr.y + vr.height - amountFull, vr.width, 
+                       amountFull);
+	  }
+
+    if (progressBar.isStringPainted() && !progressBar.getString().equals(""))
+      paintString(g, 0, 0, or.width, or.height, amountFull, insets);
+    g.setColor(saved);
+  }
+
+  /**
+   * This method is called if the painting to be done is for
+   * an indeterminate progressBar.
+   *
+   * @param g The Graphics object to paint with.
+   * @param c The JComponent to paint.
+   */
+  protected void paintIndeterminate(Graphics g, JComponent c)
+  {
+    //need to paint the box at it's current position. no text is painted since
+    //all we're doing is bouncing back and forth
+    Color saved = g.getColor();
+    Insets insets = c.getInsets();
+
+    Rectangle or = c.getBounds();
+    Rectangle vr = new Rectangle();
+    SwingUtilities.calculateInnerArea(c, vr);
+
+    g.setColor(c.getBackground());
+    g.fillRect(vr.x, vr.y, vr.width, vr.height);
+
+    boxRect = getBox(boxRect);
+
+    g.setColor(c.getForeground());
+    g.fillRect(boxRect.x, boxRect.y, boxRect.width, boxRect.height);
+
+    if (progressBar.isStringPainted() && !progressBar.getString().equals(""))
+      paintString(g, 0, 0, or.width, or.height,
+                  getAmountFull(insets, or.width, or.height), insets);
+
+    g.setColor(saved);
+  }
+
+  /**
+   * This method paints the string for the progressBar.
+   *
+   * @param g The Graphics object to paint with.
+   * @param x The x coordinate of the progressBar.
+   * @param y The y coordinate of the progressBar.
+   * @param width The width of the progressBar.
+   * @param height The height of the progressBar.
+   * @param amountFull The amount of the progressBar that has its bar filled.
+   * @param b The insets of the progressBar.
+   */
+  protected void paintString(Graphics g, int x, int y, int width, int height,
+                             int amountFull, Insets b)
+  {
+    String str = progressBar.getString();
+    int full = getAmountFull(b, width, height);
+    Point placement = getStringPlacement(g, progressBar.getString(),
+                                         x + b.left, y + b.top, 
+                                         width - b.left - b.right,
+                                         height - b.top - b.bottom);
+    Color savedColor = g.getColor();
+    Shape savedClip = g.getClip();
+    FontMetrics fm = g.getFontMetrics(progressBar.getFont());
+    
+    if (progressBar.getOrientation() == JProgressBar.VERTICAL)
+      {
+        AffineTransform rotate = AffineTransform.getRotateInstance(Math.PI / 2);
+        g.setFont(progressBar.getFont().deriveFont(rotate));
+      }
+    
+    g.setColor(getSelectionForeground());
+    g.setClip(0, 0, full + b.left, height);
+    g.drawString(str, placement.x, placement.y + fm.getAscent());
+    g.setColor(getSelectionBackground());
+    g.setClip(full + b.left, 0, width - full, height);
+    g.drawString(str, placement.x, placement.y + fm.getAscent());
+    g.setClip(savedClip);
+    g.setColor(savedColor);
+  }
+
+  /**
+   * This method sets the current animation index. If the index is greater than
+   * the number of frames, it resets to 0.
+   * 
+   * @param newValue The new animation index.
+   */
+  protected void setAnimationIndex(int newValue)
+  {
+    animationIndex = (newValue <= numFrames) ? newValue : 0;
+    progressBar.repaint();
+  }
+
+  /**
+   * This method sets the cell length.
+   *
+   * @param cellLen The cell length.
+   */
+  protected void setCellLength(int cellLen)
+  {
+    cellLength = cellLen;
+  }
+
+  /**
+   * This method sets the cell spacing.
+   *
+   * @param cellSpace The cell spacing.
+   */
+  protected void setCellSpacing(int cellSpace)
+  {
+    cellSpacing = cellSpace;
+  }
+
+  /**
+   * This method starts the animation timer. It is called
+   * when the propertyChangeListener detects that the progressBar
+   * has changed to indeterminate mode.
+   *
+   * @since 1.4
+   */
+  protected void startAnimationTimer()
+  {
+    if (animationTimer != null)
+      animationTimer.start();
+  }
+
+  /**
+   * This method stops the animation timer. It is called when
+   * the propertyChangeListener detects that the progressBar
+   * has changed to determinate mode.
+   *
+   * @since 1.4
+   */
+  protected void stopAnimationTimer()
+  {
+    if (animationTimer != null)
+      animationTimer.stop();
+    setAnimationIndex(0);
+  }
+
+  /**
+   * This method changes the settings for the progressBar to
+   * the defaults provided by the current Look and Feel.
+   */
+  protected void installDefaults()
+  {
+    LookAndFeel.installColorsAndFont(progressBar, "ProgressBar.background",
+                                     "ProgressBar.foreground",
+                                     "ProgressBar.font");
+    LookAndFeel.installBorder(progressBar, "ProgressBar.border");
+    progressBar.setOpaque(true);
+
+    selectionForeground = UIManager.getColor("ProgressBar.selectionForeground");
+    selectionBackground = UIManager.getColor("ProgressBar.selectionBackground");
+    cellLength = UIManager.getInt("ProgressBar.cellLength");
+    cellSpacing = UIManager.getInt("ProgressBar.cellSpacing");
+
+    int repaintInterval = UIManager.getInt("ProgressBar.repaintInterval");
+    int cycleTime = UIManager.getInt("ProgressBar.cycleTime");
+
+    if (cycleTime % repaintInterval != 0
+        && (cycleTime / repaintInterval) % 2 != 0)
+      {
+	int div = (cycleTime / repaintInterval) + 2;
+	div /= 2;
+	div *= 2;
+	cycleTime = div * repaintInterval;
+      }
+    setAnimationIndex(0);
+    numFrames = cycleTime / repaintInterval;
+    animationTimer.setDelay(repaintInterval);
+  }
+
+  /**
+   * The method uninstalls any defaults that were
+   * set by the current Look and Feel.
+   */
+  protected void uninstallDefaults()
+  {
+    progressBar.setFont(null);
+    progressBar.setForeground(null);
+    progressBar.setBackground(null);
+
+    selectionForeground = null;
+    selectionBackground = null;
+  }
+
+  /**
+   * This method registers listeners to all the 
+   * components that this UI delegate needs to listen to.
+   */
+  protected void installListeners()
+  {
+    changeListener = new ChangeHandler();
+    propertyListener = new PropertyChangeHandler();
+    animation = new Animator();
+
+    progressBar.addChangeListener(changeListener);
+    progressBar.addPropertyChangeListener(propertyListener);
+    animationTimer.addActionListener(animation);
+
+    ancestorListener = new AncestorHandler();
+    progressBar.addAncestorListener(ancestorListener);
+
+    componentListener = new ComponentHandler();
+    progressBar.addComponentListener(componentListener);
+  }
+
+  /**
+   * This method unregisters listeners to all the 
+   * components that were listened to.
+   */
+  protected void uninstallListeners()
+  {
+    progressBar.removeChangeListener(changeListener);
+    progressBar.removePropertyChangeListener(propertyListener);
+    animationTimer.removeActionListener(animation);
+
+    changeListener = null;
+    propertyListener = null;
+    animation = null;
+
+    if (ancestorListener != null)
+      progressBar.removeAncestorListener(ancestorListener);
+    ancestorListener = null;
+
+    if (componentListener != null)
+      progressBar.removeComponentListener(componentListener);
+    componentListener = null;
+  }
+
+  /**
+   * This method installs the UI for the given JComponent.
+   * This includes setting up defaults and listeners as
+   * well as initializing any values or objects that
+   * the UI may need.
+   *
+   * @param c The JComponent that is having this UI installed.
+   */
+  public void installUI(JComponent c)
+  {
+    super.installUI(c);
+    if (c instanceof JProgressBar)
+      {
+	progressBar = (JProgressBar) c;
+
+	animationTimer = new Timer(200, null);
+	animationTimer.setRepeats(true);
+
+	installDefaults();
+	installListeners();
+      }
+    if (progressBar.isIndeterminate())
+      startAnimationTimer();
+  }
+
+  /**
+   * This method removes the UI for the given JComponent.
+   * This includes removing any listeners or defaults
+   * that the installUI may have set up.
+   *
+   * @param c The JComponent that is having this UI uninstalled.
+   */
+  public void uninstallUI(JComponent c)
+  {
+    super.uninstallUI(c);
+    uninstallListeners();
+    uninstallDefaults();
+
+    animationTimer = null;
+    progressBar = null;
+  }
+
+}

Added: llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/BasicRadioButtonMenuItemUI.java
URL: http://llvm.org/viewvc/llvm-project/llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/BasicRadioButtonMenuItemUI.java?rev=43913&view=auto

==============================================================================
--- llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/BasicRadioButtonMenuItemUI.java (added)
+++ llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/BasicRadioButtonMenuItemUI.java Thu Nov  8 16:56:19 2007
@@ -0,0 +1,101 @@
+/* BasicRadioButtonMenuItemUI.java --
+   Copyright (C) 2002, 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., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package javax.swing.plaf.basic;
+
+import java.awt.event.MouseEvent;
+
+import javax.swing.JComponent;
+import javax.swing.JMenuItem;
+import javax.swing.MenuElement;
+import javax.swing.MenuSelectionManager;
+import javax.swing.UIDefaults;
+import javax.swing.plaf.ComponentUI;
+
+/**
+ * UI Delegator for JRadioButtonMenuItem
+ */
+public class BasicRadioButtonMenuItemUI extends BasicMenuItemUI
+{
+  /**
+   * Creates a new BasicRadioButtonMenuItemUI object.
+   */
+  public BasicRadioButtonMenuItemUI()
+  {
+    super();
+  }
+
+  /**
+    * Factory method to create a BasicRadioButtonMenuItemUI for the given {@link
+    * JComponent}, which should be a JRadioButtonMenuItem.
+    *
+    * @param b The {@link JComponent} a UI is being created for.
+    *
+    * @return A BasicRadioButtonMenuItemUI for the {@link JComponent}.
+    */
+  public static ComponentUI createUI(JComponent b)
+  {
+    return new BasicRadioButtonMenuItemUI();
+  }
+
+  /**
+   * Returns the prefix for entries in the {@link UIDefaults} table.
+   *
+   * @return "RadioButtonMenuItem"
+   */
+  protected String getPropertyPrefix()
+  {
+    return "RadioButtonMenuItem";
+  }
+
+  /**
+   * DOCUMENT ME!
+   *
+   * @param item DOCUMENT ME!
+   * @param e DOCUMENT ME!
+   * @param path DOCUMENT ME!
+   * @param manager DOCUMENT ME!
+   */
+  public void processMouseEvent(JMenuItem item, MouseEvent e,
+                                MenuElement[] path,
+                                MenuSelectionManager manager)
+  {
+    // TODO: May not be implemented properly.
+    item.processMouseEvent(e, path, manager);
+  }
+}

Added: llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/BasicRadioButtonUI.java
URL: http://llvm.org/viewvc/llvm-project/llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/BasicRadioButtonUI.java?rev=43913&view=auto

==============================================================================
--- llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/BasicRadioButtonUI.java (added)
+++ llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/BasicRadioButtonUI.java Thu Nov  8 16:56:19 2007
@@ -0,0 +1,226 @@
+/* BasicRadioButtonUI.java
+   Copyright (C) 2002, 2004, 2006, Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package javax.swing.plaf.basic;
+
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.Font;
+import java.awt.Graphics;
+import java.awt.Insets;
+import java.awt.Rectangle;
+
+import javax.swing.AbstractButton;
+import javax.swing.ButtonModel;
+import javax.swing.Icon;
+import javax.swing.JComponent;
+import javax.swing.SwingUtilities;
+import javax.swing.UIManager;
+import javax.swing.plaf.ComponentUI;
+
+/**
+ * The BasicLookAndFeel UI implementation for
+ * {@link javax.swing.JRadioButton}s.
+ */
+public class BasicRadioButtonUI extends BasicToggleButtonUI
+{
+  /**
+   * The default icon for JRadioButtons. The default icon displays the usual
+   * RadioButton and is sensible to the selection state of the button,
+   * and can be used both as normal icon as well as selectedIcon.
+   */
+  protected Icon icon;
+
+  /**
+   * Creates and returns a new instance of <code>BasicRadioButtonUI</code>.
+   *
+   * @return a new instance of <code>BasicRadioButtonUI</code>
+   */
+  public static ComponentUI createUI(final JComponent c)  
+  {
+    return new BasicRadioButtonUI();
+  }
+
+  /**
+   * Creates a new instance of <code>BasicButtonUI</code>.
+   */
+  public BasicRadioButtonUI()
+  {
+    icon = getDefaultIcon();
+  }
+
+  /**
+   * Installs defaults from the Look & Feel table on the specified
+   * button.
+   *
+   * @param b the button on which to install the defaults
+   */
+  protected void installDefaults(AbstractButton b)
+  {
+    super.installDefaults(b);
+  }
+
+  /**
+   * Returns the prefix used for UIDefaults properties. This is
+   * <code>RadioButton</code> in this case.
+   *
+   * @return the prefix used for UIDefaults properties
+   */
+  protected String getPropertyPrefix()
+  {
+    return "RadioButton.";
+  }
+
+  /**
+   * Returns the default icon for JRadioButtons.
+   * The default icon displays the usual
+   * RadioButton and is sensible to the selection state of the button,
+   * and can be used both as normal icon as well as selectedIcon.
+   *
+   * @return the default icon for JRadioButtons
+   */
+  public Icon getDefaultIcon()
+  {
+    return UIManager.getIcon(getPropertyPrefix() + "icon");
+  }
+
+  /**
+   * Paints the RadioButton.
+   *
+   * @param g the Graphics context to paint with
+   * @param c the button to paint
+   */
+  public void paint(Graphics g, JComponent c)
+  {
+    AbstractButton b = (AbstractButton) c;
+
+    Rectangle tr = new Rectangle();
+    Rectangle ir = new Rectangle();
+    Rectangle vr = new Rectangle();
+
+    Font f = c.getFont();
+
+    g.setFont(f);
+
+    ButtonModel m = b.getModel();
+    // FIXME: Do a filtering on any customized icon if the following property
+    // is set.
+    boolean enabled = b.isEnabled();
+    
+    Icon currentIcon = b.getIcon();
+
+    if (currentIcon == null)
+      {
+        currentIcon = getDefaultIcon();
+      }
+    
+    SwingUtilities.calculateInnerArea(b, vr);
+    String text = SwingUtilities.layoutCompoundLabel(c, g.getFontMetrics(f), 
+       b.getText(), currentIcon,
+       b.getVerticalAlignment(), b.getHorizontalAlignment(),
+       b.getVerticalTextPosition(), b.getHorizontalTextPosition(),
+       vr, ir, tr, b.getIconTextGap() + defaultTextShiftOffset);
+    
+    currentIcon.paintIcon(c, g, ir.x, ir.y);
+    
+    if (text != null)
+      paintText(g, b, tr, text);
+    if (b.hasFocus() && b.isFocusPainted() && m.isEnabled())
+      paintFocus(g, tr, c.getSize());
+  }
+  
+  public Dimension getPreferredSize(JComponent c)
+  {
+    // This is basically the same code as in
+    // BasicGraphicsUtils.getPreferredButtonSize() but takes the default icon
+    // property into account. JRadioButton and subclasses always have an icon:
+    // the check box. If the user explicitly changes it with setIcon() that
+    // one will be used for layout calculations and painting instead.
+    // The other icon properties are ignored.
+    AbstractButton b = (AbstractButton) c;
+    
+    Rectangle contentRect;
+    Rectangle viewRect;
+    Rectangle iconRect = new Rectangle();
+    Rectangle textRect = new Rectangle();
+    Insets insets = b.getInsets();
+    
+    Icon i = b.getIcon();
+    if (i == null)
+      i = getDefaultIcon(); 
+    
+    viewRect = new Rectangle();
+
+    SwingUtilities.layoutCompoundLabel(
+      b, // for the component orientation
+      b.getFontMetrics(b.getFont()),
+      b.getText(),
+      i,
+      b.getVerticalAlignment(), 
+      b.getHorizontalAlignment(),
+      b.getVerticalTextPosition(),
+      b.getHorizontalTextPosition(),
+      viewRect, iconRect, textRect,
+      defaultTextIconGap + defaultTextShiftOffset);
+
+    contentRect = textRect.union(iconRect);
+    
+    return new Dimension(insets.left
+                         + contentRect.width 
+                         + insets.right + b.getHorizontalAlignment(),
+                         insets.top
+                         + contentRect.height 
+                         + insets.bottom);
+  }
+
+  /**
+   * Paints the focus indicator for JRadioButtons.
+   *
+   * @param g the graphics context
+   * @param tr the rectangle for the text label
+   * @param size the size of the <code>JRadioButton</code> component.
+   */
+  protected void paintFocus(Graphics g, Rectangle tr, Dimension size)
+  {
+    Color focusColor = UIManager.getColor(getPropertyPrefix() + ".focus");
+    Color saved = g.getColor();
+    g.setColor(focusColor);
+    g.drawRect(tr.x, tr.y, tr.width, tr.height);
+    g.setColor(saved);
+  }
+}

Added: llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/BasicRootPaneUI.java
URL: http://llvm.org/viewvc/llvm-project/llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/BasicRootPaneUI.java?rev=43913&view=auto

==============================================================================
--- llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/BasicRootPaneUI.java (added)
+++ llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/BasicRootPaneUI.java Thu Nov  8 16:56:19 2007
@@ -0,0 +1,292 @@
+/* BasicRootPaneUI.java --
+   Copyright (C) 2002, 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., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package javax.swing.plaf.basic;
+
+import java.awt.event.ActionEvent;
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+
+import javax.swing.AbstractAction;
+import javax.swing.ButtonModel;
+import javax.swing.InputMap;
+import javax.swing.JButton;
+import javax.swing.JComponent;
+import javax.swing.JRootPane;
+import javax.swing.LookAndFeel;
+import javax.swing.SwingUtilities;
+import javax.swing.UIManager;
+import javax.swing.plaf.ActionMapUIResource;
+import javax.swing.plaf.ComponentInputMapUIResource;
+import javax.swing.plaf.ComponentUI;
+import javax.swing.plaf.RootPaneUI;
+
+public class BasicRootPaneUI extends RootPaneUI
+  implements PropertyChangeListener
+{
+
+  /**
+   * Performed when the user activates the default button inside the JRootPane,
+   * usually by pressing 'ENTER'.
+   */
+  private class DefaultPressAction
+    extends AbstractAction
+  {
+    /**
+     * The JRootPane for which this action should be installed.
+     */
+    private JRootPane rootPane;
+
+    /**
+     * Creates a new DefaultPressAction for the specified JRootPane.
+     */
+    DefaultPressAction(JRootPane rp)
+    {
+      rootPane = rp;
+    }
+
+    /**
+     * Performes the action.
+     */
+    public void actionPerformed(ActionEvent ev)
+    {
+      JButton b = rootPane.getDefaultButton();
+      if (b != null)
+        {
+          ButtonModel m = b.getModel();
+          m.setArmed(true);
+          m.setPressed(true);
+        }
+    }
+  }
+
+  /**
+   * Performed when the user activates the default button inside the JRootPane,
+   * usually by releasing 'ENTER'.
+   */
+  private class DefaultReleaseAction
+    extends AbstractAction
+  {
+    /**
+     * The JRootPane for which this action should be installed.
+     */
+    private JRootPane rootPane;
+
+    /**
+     * Creates a new DefaultReleaseAction for the specified JRootPane.
+     */
+    DefaultReleaseAction(JRootPane rp)
+    {
+      rootPane = rp;
+    }
+
+    /**
+     * Performes the action.
+     */
+    public void actionPerformed(ActionEvent ev)
+    {
+      JButton b = rootPane.getDefaultButton();
+      if (b != null)
+        {
+          ButtonModel m = b.getModel();
+          m.setPressed(false);
+          m.setArmed(false);
+        }
+    }
+  }
+
+  public static ComponentUI createUI(JComponent x) 
+  {
+    return new BasicRootPaneUI();
+  }
+
+  public void installUI(JComponent c)
+  {
+    super.installUI(c);
+    if (c instanceof JRootPane)
+      {
+        JRootPane rp = (JRootPane) c;
+        installDefaults(rp);
+        installComponents(rp);
+        installListeners(rp);
+        installKeyboardActions(rp);
+      }
+  }
+
+  /**
+   * Installs the look and feel defaults for JRootPane.
+   *
+   * @param rp the root pane to install the defaults to
+   */
+  protected void installDefaults(JRootPane rp)
+  {
+    // TODO: What to do here, if anything? (might be a hook method)
+  }
+
+  /**
+   * Installs additional look and feel components to the root pane.
+   *
+   * @param rp the root pane to install the components to
+   */
+  protected void installComponents(JRootPane rp)
+  {
+    // All components are initialized in the JRootPane constructor, and since
+    // the createXXXPane methods are protected, I see no reasonable way,
+    // and no need to initialize them here. This method is here anyway
+    // for compatibility and to provide the necessary hooks to subclasses.
+  }
+
+  /**
+   * Installs any look and feel specific listeners on the root pane.
+   *
+   * @param rp the root pane to install the listeners to
+   */
+  protected void installListeners(JRootPane rp)
+  {
+    rp.addPropertyChangeListener(this);
+  }
+
+  /**
+   * Installs look and feel keyboard actions on the root pane.
+   *
+   * @param rp the root pane to install the keyboard actions to
+   */
+  protected void installKeyboardActions(JRootPane rp)
+  {
+    // Install the keyboard actions.
+    ActionMapUIResource am = new ActionMapUIResource();
+    am.put("press", new DefaultPressAction(rp));
+    am.put("release", new DefaultReleaseAction(rp));
+    SwingUtilities.replaceUIActionMap(rp, am);
+
+    // Install the input map from the UIManager. It seems like the actual
+    // bindings are installed in the JRootPane only when the defaultButton
+    // property receives a value. So we also only install an empty
+    // input map here, and fill it in propertyChange.
+    ComponentInputMapUIResource im = new ComponentInputMapUIResource(rp);
+    SwingUtilities.replaceUIInputMap(rp, JComponent.WHEN_IN_FOCUSED_WINDOW,
+                                     im);
+  }
+
+  public void propertyChange(PropertyChangeEvent event)
+  {
+    JRootPane source = (JRootPane) event.getSource();
+    String propertyName = event.getPropertyName();
+    if (propertyName.equals("defaultButton"))
+      {
+        Object newValue = event.getNewValue();
+        InputMap im =
+          SwingUtilities.getUIInputMap(source,
+                                       JComponent.WHEN_IN_FOCUSED_WINDOW);
+        if (newValue != null)
+          {
+            Object[] keybindings = (Object[]) UIManager.get(
+                "RootPane.defaultButtonWindowKeyBindings");
+            LookAndFeel.loadKeyBindings(im, keybindings);
+          }
+        else
+          {
+            im.clear();
+          }
+      }
+  }
+
+  /**
+   * Uninstalls this UI from the root pane. This calls
+   * {@link #uninstallDefaults}, {@link #uninstallComponents},
+   * {@link #uninstallListeners}, {@link #uninstallKeyboardActions}
+   * in this order.
+   *
+   * @param c the root pane to uninstall the UI from
+   */
+  public void uninstallUI(JComponent c)
+  {
+    super.uninstallUI(c);
+    if (c instanceof JRootPane)
+      {
+        JRootPane rp = (JRootPane) c;
+        uninstallDefaults(rp);
+        uninstallComponents(rp);
+        uninstallListeners(rp);
+        uninstallKeyboardActions(rp);
+      }
+  }
+
+  /**
+   * Uninstalls the look and feel defaults that have been installed in
+   * {@link #installDefaults}.
+   *
+   * @param rp the root pane to uninstall the defaults from
+   */
+  protected void uninstallDefaults(JRootPane rp)
+  {
+    // We do nothing here.
+  }
+
+  /**
+   * Uninstalls look and feel components from the root pane.
+   *
+   * @param rp the root pane to uninstall the components from
+   */
+  protected void uninstallComponents(JRootPane rp)
+  {
+    // We do nothing here.
+  }
+
+  /**
+   * Uninstalls any look and feel specific listeners from the root pane.
+   *
+   * @param rp the root pane to uninstall the listeners from
+   */
+  protected void uninstallListeners(JRootPane rp)
+  {
+    rp.removePropertyChangeListener(this);
+  }
+
+  /**
+   * Uninstalls look and feel keyboard actions from the root pane.
+   *
+   * @param rp the root pane to uninstall the keyboard actions from
+   */
+  protected void uninstallKeyboardActions(JRootPane rp)
+  {
+    SwingUtilities.replaceUIActionMap(rp, null);
+    SwingUtilities.replaceUIInputMap(rp, JComponent.WHEN_IN_FOCUSED_WINDOW,
+                                     null);
+  }
+}

Added: llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/BasicScrollBarUI.java
URL: http://llvm.org/viewvc/llvm-project/llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/BasicScrollBarUI.java?rev=43913&view=auto

==============================================================================
--- llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/BasicScrollBarUI.java (added)
+++ llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/BasicScrollBarUI.java Thu Nov  8 16:56:19 2007
@@ -0,0 +1,1450 @@
+/* BasicScrollBarUI.java --
+   Copyright (C) 2004, 2005, 2006,  Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package javax.swing.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.LayoutManager;
+import java.awt.Rectangle;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseMotionListener;
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+
+import javax.swing.AbstractAction;
+import javax.swing.ActionMap;
+import javax.swing.BoundedRangeModel;
+import javax.swing.InputMap;
+import javax.swing.JButton;
+import javax.swing.JComponent;
+import javax.swing.JScrollBar;
+import javax.swing.JSlider;
+import javax.swing.LookAndFeel;
+import javax.swing.SwingConstants;
+import javax.swing.SwingUtilities;
+import javax.swing.Timer;
+import javax.swing.UIManager;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+import javax.swing.plaf.ActionMapUIResource;
+import javax.swing.plaf.ComponentUI;
+import javax.swing.plaf.ScrollBarUI;
+
+/**
+ * The Basic Look and Feel UI delegate for JScrollBar.
+ */
+public class BasicScrollBarUI extends ScrollBarUI implements LayoutManager,
+                                                             SwingConstants
+{
+  /**
+   * A helper class that listens to the two JButtons on each end of the
+   * JScrollBar.
+   */
+  protected class ArrowButtonListener extends MouseAdapter
+  {
+   
+    /**
+     * Move the thumb in the direction specified by the  button's arrow. If
+     * this button is held down, then it should keep moving the thumb.
+     *
+     * @param e The MouseEvent fired by the JButton.
+     */
+    public void mousePressed(MouseEvent e)
+    {
+      scrollTimer.stop();
+      scrollListener.setScrollByBlock(false);
+      if (e.getSource() == incrButton)
+          scrollListener.setDirection(POSITIVE_SCROLL);
+      else if (e.getSource() == decrButton)
+          scrollListener.setDirection(NEGATIVE_SCROLL);
+      scrollTimer.setDelay(100);
+      scrollTimer.start();
+    }
+
+    /**
+     * Stops the thumb when the JButton is released.
+     *
+     * @param e The MouseEvent fired by the JButton.
+     */
+    public void mouseReleased(MouseEvent e)
+    {
+      scrollTimer.stop();
+      scrollTimer.setDelay(300);
+      if (e.getSource() == incrButton)
+          scrollByUnit(POSITIVE_SCROLL);
+      else if (e.getSource() == decrButton)
+        scrollByUnit(NEGATIVE_SCROLL);
+    }
+  }
+
+  /**
+   * A helper class that listens to the ScrollBar's model for ChangeEvents.
+   */
+  protected class ModelListener implements ChangeListener
+  {
+    /**
+     * Called when the model changes.
+     *
+     * @param e The ChangeEvent fired by the model.
+     */
+    public void stateChanged(ChangeEvent e)
+    {
+      calculatePreferredSize();
+      updateThumbRect();
+      scrollbar.repaint();
+    }
+  }
+
+  /**
+   * A helper class that listens to the ScrollBar's properties.
+   */
+  public class PropertyChangeHandler implements PropertyChangeListener
+  {
+    /**
+     * Called when one of the ScrollBar's properties change.
+     *
+     * @param e The PropertyChangeEvent fired by the ScrollBar.
+     */
+    public void propertyChange(PropertyChangeEvent e)
+    {
+      if (e.getPropertyName().equals("model"))
+        {
+          ((BoundedRangeModel) e.getOldValue()).removeChangeListener(modelListener);
+          scrollbar.getModel().addChangeListener(modelListener);
+          updateThumbRect();
+        }
+      else if (e.getPropertyName().equals("orientation"))
+        {
+          uninstallListeners();
+          uninstallComponents();
+          uninstallDefaults();
+          installDefaults();
+          installComponents();
+          installListeners();
+        }
+      else if (e.getPropertyName().equals("enabled"))
+        {
+          Boolean b = (Boolean) e.getNewValue();
+          if (incrButton != null)
+            incrButton.setEnabled(b.booleanValue());
+          if (decrButton != null)
+            decrButton.setEnabled(b.booleanValue());
+        }
+    }
+  }
+
+  /**
+   * A helper class that listens for events from the timer that is used to
+   * move the thumb.
+   */
+  protected class ScrollListener implements ActionListener
+  {
+    /** The direction the thumb moves in. */
+    private transient int direction;
+
+    /** Whether movement will be in blocks. */
+    private transient boolean block;
+
+    /**
+     * Creates a new ScrollListener object. The default is scrolling
+     * positively with block movement.
+     */
+    public ScrollListener()
+    {
+      direction = POSITIVE_SCROLL;
+      block = true;
+    }
+
+    /**
+     * Creates a new ScrollListener object using the given direction and
+     * block.
+     *
+     * @param dir The direction to move in.
+     * @param block Whether movement will be in blocks.
+     */
+    public ScrollListener(int dir, boolean block)
+    {
+      direction = dir;
+      this.block = block;
+    }
+
+    /**
+     * Sets the direction to scroll in.
+     *
+     * @param direction The direction to scroll in.
+     */
+    public void setDirection(int direction)
+    {
+      this.direction = direction;
+    }
+
+    /**
+     * Sets whether scrolling will be done in blocks.
+     *
+     * @param block Whether scrolling will be in blocks.
+     */
+    public void setScrollByBlock(boolean block)
+    {
+      this.block = block;
+    }
+
+    /**
+     * Called every time the timer reaches its interval.
+     *
+     * @param e The ActionEvent fired by the timer.
+     */
+    public void actionPerformed(ActionEvent e)
+    {
+      if (block)
+        {
+          // Only need to check it if it's block scrolling
+          // We only block scroll if the click occurs
+          // in the track.
+          if (!trackListener.shouldScroll(direction))
+            {
+              trackHighlight = NO_HIGHLIGHT;
+              scrollbar.repaint();
+              return;
+            }
+            scrollByBlock(direction);
+        }
+      else
+        scrollByUnit(direction);
+    }
+  }
+
+  /**
+   * Helper class that listens for movement on the track.
+   */
+  protected class TrackListener extends MouseAdapter
+    implements MouseMotionListener
+  {
+    /** The current X coordinate of the mouse. */
+    protected int currentMouseX;
+
+    /** The current Y coordinate of the mouse. */
+    protected int currentMouseY;
+
+    /**
+     * The offset between the current mouse cursor and the  current value of
+     * the scrollbar.
+     */
+    protected int offset;
+
+    /**
+     * This method is called when the mouse is being dragged.
+     *
+     * @param e The MouseEvent given.
+     */
+    public void mouseDragged(MouseEvent e)
+    {
+      currentMouseX = e.getX();
+      currentMouseY = e.getY();
+      if (scrollbar.getValueIsAdjusting())
+        {
+	  int value;
+	  if (scrollbar.getOrientation() == SwingConstants.HORIZONTAL)
+	    value = valueForXPosition(currentMouseX) - offset;
+	  else
+	    value = valueForYPosition(currentMouseY) - offset;
+
+	  scrollbar.setValue(value);
+        }
+    }
+
+    /**
+     * This method is called when the mouse is moved.
+     *
+     * @param e The MouseEvent given.
+     */
+    public void mouseMoved(MouseEvent e)
+    {
+      if (thumbRect.contains(e.getPoint()))
+        thumbRollover = true;
+      else
+        thumbRollover = false;
+    }
+
+    /**
+     * This method is called when the mouse is pressed. When it is pressed,
+     * the thumb should move in blocks towards the cursor.
+     *
+     * @param e The MouseEvent given.
+     */
+    public void mousePressed(MouseEvent e)
+    {
+      currentMouseX = e.getX();
+      currentMouseY = e.getY();
+
+      int value;
+      if (scrollbar.getOrientation() == SwingConstants.HORIZONTAL)
+	value = valueForXPosition(currentMouseX);
+      else
+	value = valueForYPosition(currentMouseY);
+
+      if (! thumbRect.contains(e.getPoint()))
+        {
+	  scrollTimer.stop();
+	  scrollListener.setScrollByBlock(true);
+	  if (value > scrollbar.getValue())
+	    {
+	      trackHighlight = INCREASE_HIGHLIGHT;
+	      scrollListener.setDirection(POSITIVE_SCROLL);
+	    }
+	  else
+	    {
+	      trackHighlight = DECREASE_HIGHLIGHT;
+	      scrollListener.setDirection(NEGATIVE_SCROLL);
+	    }
+      scrollTimer.setDelay(100);
+	  scrollTimer.start();
+        }
+      else
+        {
+	  // We'd like to keep track of where the cursor
+	  // is inside the thumb.
+	  // This works because the scrollbar's value represents 
+	  // "lower" edge of the thumb. The value at which
+	  // the cursor is at must be greater or equal
+	  // to that value.
+
+      scrollListener.setScrollByBlock(false);
+	  scrollbar.setValueIsAdjusting(true);
+      offset = value - scrollbar.getValue();
+        }
+      scrollbar.repaint();
+    }
+
+    /**
+     * This method is called when the mouse is released. It should stop
+     * movement on the thumb
+     *
+     * @param e The MouseEvent given.
+     */
+    public void mouseReleased(MouseEvent e)
+    {
+      scrollTimer.stop();
+      scrollTimer.setDelay(300);
+      currentMouseX = e.getX();
+      currentMouseY = e.getY();
+
+      if (shouldScroll(POSITIVE_SCROLL))
+        scrollByBlock(POSITIVE_SCROLL);
+      else if (shouldScroll(NEGATIVE_SCROLL))
+        scrollByBlock(NEGATIVE_SCROLL);
+
+      trackHighlight = NO_HIGHLIGHT;
+      scrollListener.setScrollByBlock(false);
+      scrollbar.setValueIsAdjusting(true);
+      scrollbar.repaint();
+    }
+
+    /**
+     * A helper method that decides whether we should keep scrolling in the
+     * given direction.
+     *
+     * @param direction The direction to check for.
+     *
+     * @return Whether the thumb should keep scrolling.
+     */
+    boolean shouldScroll(int direction)
+    {
+      int value;
+      if (scrollbar.getOrientation() == HORIZONTAL)
+	value = valueForXPosition(currentMouseX);
+      else
+	value = valueForYPosition(currentMouseY);
+
+      if (thumbRect.contains(currentMouseX, currentMouseY))
+        return false;
+      
+      if (direction == POSITIVE_SCROLL)
+	return value > scrollbar.getValue();
+      else
+	return value < scrollbar.getValue();
+    }
+  }
+
+  /** The listener that listens to the JButtons. */
+  protected ArrowButtonListener buttonListener;
+
+  /** The listener that listens to the model. */
+  protected ModelListener modelListener;
+
+  /** The listener that listens to the scrollbar for property changes. */
+  protected PropertyChangeListener propertyChangeListener;
+
+  /** The listener that listens to the timer. */
+  protected ScrollListener scrollListener;
+
+  /** The listener that listens for MouseEvents on the track. */
+  protected TrackListener trackListener;
+
+  /** The JButton that decrements the scrollbar's value. */
+  protected JButton decrButton;
+
+  /** The JButton that increments the scrollbar's value. */
+  protected JButton incrButton;
+
+  /** The dimensions of the maximum thumb size. */
+  protected Dimension maximumThumbSize;
+
+  /** The dimensions of the minimum thumb size. */
+  protected Dimension minimumThumbSize;
+
+  /** The color of the thumb. */
+  protected Color thumbColor;
+
+  /** The outer shadow of the thumb. */
+  protected Color thumbDarkShadowColor;
+
+  /** The top and left edge color for the thumb. */
+  protected Color thumbHighlightColor;
+
+  /** The outer light shadow for the thumb. */
+  protected Color thumbLightShadowColor;
+
+  /** The color that is used when the mouse press occurs in the track. */
+  protected Color trackHighlightColor;
+
+  /** The color of the track. */
+  protected Color trackColor;
+
+  /** The size and position of the track. */
+  protected Rectangle trackRect;
+
+  /** The size and position of the thumb. */
+  protected Rectangle thumbRect;
+
+  /** Indicates that the decrease highlight should be painted. */
+  protected static final int DECREASE_HIGHLIGHT = 1;
+
+  /** Indicates that the increase highlight should be painted. */
+  protected static final int INCREASE_HIGHLIGHT = 2;
+
+  /** Indicates that no highlight should be painted. */
+  protected static final int NO_HIGHLIGHT = 0;
+
+  /** Indicates that the scrolling direction is positive. */
+  private static final int POSITIVE_SCROLL = 1;
+
+  /** Indicates that the scrolling direction is negative. */
+  private static final int NEGATIVE_SCROLL = -1;
+
+  /** The cached preferred size for the scrollbar. */
+  private transient Dimension preferredSize;
+
+  /** The current highlight status. */
+  protected int trackHighlight;
+
+  /** FIXME: Use this for something (presumably mouseDragged) */
+  protected boolean isDragging;
+
+  /** The timer used to move the thumb when the mouse is held. */
+  protected Timer scrollTimer;
+
+  /** The scrollbar this UI is acting for. */
+  protected JScrollBar scrollbar;
+  
+  /** True if the mouse is over the thumb. */
+  boolean thumbRollover;
+
+  /**
+   * This method adds a component to the layout.
+   *
+   * @param name The name to associate with the component that is added.
+   * @param child The Component to add.
+   */
+  public void addLayoutComponent(String name, Component child)
+  {
+    // You should not be adding stuff to this component.
+    // The contents are fixed.
+  }
+
+  /**
+   * This method configures the scrollbar's colors. This can be  done by
+   * looking up the standard colors from the Look and Feel defaults.
+   */
+  protected void configureScrollBarColors()
+  {
+    trackColor = UIManager.getColor("ScrollBar.track");
+    trackHighlightColor = UIManager.getColor("ScrollBar.trackHighlight");
+    thumbColor = UIManager.getColor("ScrollBar.thumb");
+    thumbHighlightColor = UIManager.getColor("ScrollBar.thumbHighlight");
+    thumbDarkShadowColor = UIManager.getColor("ScrollBar.thumbDarkShadow");
+    thumbLightShadowColor = UIManager.getColor("ScrollBar.thumbShadow");
+  }
+
+  /**
+   * This method creates an ArrowButtonListener.
+   *
+   * @return A new ArrowButtonListener.
+   */
+  protected ArrowButtonListener createArrowButtonListener()
+  {
+    return new ArrowButtonListener();
+  }
+
+  /**
+   * This method creates a new JButton with the appropriate icon for the
+   * orientation.
+   *
+   * @param orientation The orientation this JButton uses.
+   *
+   * @return The increase JButton.
+   */
+  protected JButton createIncreaseButton(int orientation)
+  {
+    return new BasicArrowButton(orientation);
+  }
+
+  /**
+   * This method creates a new JButton with the appropriate icon for the
+   * orientation.
+   *
+   * @param orientation The orientation this JButton uses.
+   *
+   * @return The decrease JButton.
+   */
+  protected JButton createDecreaseButton(int orientation)
+  {
+    return new BasicArrowButton(orientation);
+  }
+
+  /**
+   * This method creates a new ModelListener.
+   *
+   * @return A new ModelListener.
+   */
+  protected ModelListener createModelListener()
+  {
+    return new ModelListener();
+  }
+
+  /**
+   * This method creates a new PropertyChangeListener.
+   *
+   * @return A new PropertyChangeListener.
+   */
+  protected PropertyChangeListener createPropertyChangeListener()
+  {
+    return new PropertyChangeHandler();
+  }
+
+  /**
+   * This method creates a new ScrollListener.
+   *
+   * @return A new ScrollListener.
+   */
+  protected ScrollListener createScrollListener()
+  {
+    return new ScrollListener();
+  }
+
+  /**
+   * This method creates a new TrackListener.
+   *
+   * @return A new TrackListener.
+   */
+  protected TrackListener createTrackListener()
+  {
+    return new TrackListener();
+  }
+
+  /**
+   * This method returns a new BasicScrollBarUI.
+   *
+   * @param c The JComponent to create a UI for.
+   *
+   * @return A new BasicScrollBarUI.
+   */
+  public static ComponentUI createUI(JComponent c)
+  {
+    return new BasicScrollBarUI();
+  }
+
+  /**
+   * This method returns the maximum size for this JComponent.
+   *
+   * @param c The JComponent to measure the maximum size for.
+   *
+   * @return The maximum size for the component.
+   */
+  public Dimension getMaximumSize(JComponent c)
+  {
+    return new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE);
+  }
+
+  /**
+   * This method returns the maximum thumb size.
+   *
+   * @return The maximum thumb size.
+   */
+  protected Dimension getMaximumThumbSize()
+  {
+    return maximumThumbSize;
+  }
+
+  /**
+   * This method returns the minimum size for this JComponent.
+   *
+   * @param c The JComponent to measure the minimum size for.
+   *
+   * @return The minimum size for the component.
+   */
+  public Dimension getMinimumSize(JComponent c)
+  {
+    return getPreferredSize(c);
+  }
+
+  /**
+   * This method returns the minimum thumb size.
+   *
+   * @return The minimum thumb size.
+   */
+  protected Dimension getMinimumThumbSize()
+  {
+    return minimumThumbSize;
+  }
+
+  /**
+   * This method calculates the preferred size since calling
+   * getPreferredSize() returns a cached value.
+   * This is package-private to avoid an accessor method.
+   */
+  void calculatePreferredSize()
+  {
+    int height;
+    int width;
+    height = width = 0;
+
+    if (scrollbar.getOrientation() == SwingConstants.HORIZONTAL)
+      {
+        width += incrButton.getPreferredSize().getWidth();
+        width += decrButton.getPreferredSize().getWidth();
+        width += 16;
+        height = UIManager.getInt("ScrollBar.width");
+      }
+    else
+      {
+        height += incrButton.getPreferredSize().getHeight();
+        height += decrButton.getPreferredSize().getHeight();
+        height += 16;
+        width = UIManager.getInt("ScrollBar.width");
+      }
+
+    Insets insets = scrollbar.getInsets();
+
+    height += insets.top + insets.bottom;
+    width += insets.left + insets.right;
+
+    preferredSize = new Dimension(width, height);
+  }
+
+  /**
+   * This method returns a cached value of the preferredSize. The only
+   * restrictions are: If the scrollbar is horizontal, the height should be
+   * the maximum of the height of the JButtons and  the minimum width of the
+   * thumb. For vertical scrollbars, the  calculation is similar (swap width
+   * for height and vice versa).
+   *
+   * @param c The JComponent to measure.
+   *
+   * @return The preferredSize.
+   */
+  public Dimension getPreferredSize(JComponent c)
+  {
+    calculatePreferredSize();
+    return preferredSize;
+  }
+
+  /**
+   * This method returns the thumb's bounds based on the  current value of the
+   * scrollbar. This method updates the cached value and returns that.
+   *
+   * @return The thumb bounds.
+   */
+  protected Rectangle getThumbBounds()
+  {
+    return thumbRect;
+  }
+
+  /**
+   * This method calculates the bounds of the track. This method updates the
+   * cached value and returns it.
+   *
+   * @return The track's bounds.
+   */
+  protected Rectangle getTrackBounds()
+  {
+    return trackRect;
+  }
+
+  /**
+   * This method installs any addition Components that  are a part of or
+   * related to this scrollbar.
+   */
+  protected void installComponents()
+  {
+    int orientation = scrollbar.getOrientation();
+    switch (orientation)
+      {
+      case JScrollBar.HORIZONTAL:
+        incrButton = createIncreaseButton(EAST);
+        decrButton = createDecreaseButton(WEST);
+        break;
+      default:
+        incrButton = createIncreaseButton(SOUTH);
+        decrButton = createDecreaseButton(NORTH);
+        break;
+      }
+
+    if (incrButton != null)
+      scrollbar.add(incrButton);
+    if (decrButton != null)
+      scrollbar.add(decrButton);
+  }
+
+  /**
+   * This method installs the defaults for the scrollbar specified by the
+   * Basic Look and Feel.
+   */
+  protected void installDefaults()
+  {
+    LookAndFeel.installColors(scrollbar, "ScrollBar.background",
+                              "ScrollBar.foreground");
+    LookAndFeel.installBorder(scrollbar, "ScrollBar.border");
+    scrollbar.setOpaque(true);
+    scrollbar.setLayout(this);
+
+    thumbColor = UIManager.getColor("ScrollBar.thumb");
+    thumbDarkShadowColor = UIManager.getColor("ScrollBar.thumbDarkShadow");
+    thumbHighlightColor = UIManager.getColor("ScrollBar.thumbHighlight");
+    thumbLightShadowColor = UIManager.getColor("ScrollBar.thumbShadow");
+
+    maximumThumbSize = UIManager.getDimension("ScrollBar.maximumThumbSize");
+    minimumThumbSize = UIManager.getDimension("ScrollBar.minimumThumbSize");
+  }
+
+  /**
+   * Installs the input map from the look and feel defaults, and a 
+   * corresponding action map.  Note the the keyboard bindings will only
+   * work when the {@link JScrollBar} component has the focus, which is rare.
+   */
+  protected void installKeyboardActions()
+  {
+    InputMap keyMap = getInputMap(
+        JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
+    SwingUtilities.replaceUIInputMap(scrollbar, 
+        JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT, keyMap);
+    ActionMap map = getActionMap();
+    SwingUtilities.replaceUIActionMap(scrollbar, map);
+  }
+
+  /**
+   * Uninstalls the input map and action map installed by
+   * {@link #installKeyboardActions()}.
+   */
+  protected void uninstallKeyboardActions()
+  {
+    SwingUtilities.replaceUIActionMap(scrollbar, null);
+    SwingUtilities.replaceUIInputMap(scrollbar, 
+        JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT, null);
+  }
+
+  InputMap getInputMap(int condition) 
+  {
+    if (condition == JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT)
+      return (InputMap) UIManager.get("ScrollBar.focusInputMap");
+    return null;
+  }
+  
+  /**
+   * Returns the action map for the {@link JScrollBar}.  All scroll bars 
+   * share a single action map which is created the first time this method is 
+   * called, then stored in the UIDefaults table for subsequent access.
+   * 
+   * @return The shared action map.
+   */
+  ActionMap getActionMap() 
+  {
+    ActionMap map = (ActionMap) UIManager.get("ScrollBar.actionMap");
+
+    if (map == null) // first time here
+      {
+        map = createActionMap();
+        if (map != null)
+          UIManager.put("ScrollBar.actionMap", map);
+      }
+    return map;
+  }
+
+  /**
+   * Creates the action map shared by all {@link JSlider} instances.
+   * This method is called once by {@link #getActionMap()} when it 
+   * finds no action map in the UIDefaults table...after the map is 
+   * created, it gets added to the defaults table so that subsequent 
+   * calls to {@link #getActionMap()} will return the same shared 
+   * instance.
+   * 
+   * @return The action map.
+   */
+  ActionMap createActionMap()
+  {
+    ActionMap map = new ActionMapUIResource();
+    map.put("positiveUnitIncrement", 
+            new AbstractAction("positiveUnitIncrement") {
+              public void actionPerformed(ActionEvent event)
+              {
+                JScrollBar sb = (JScrollBar) event.getSource();
+                if (sb.isVisible()) 
+                  {
+                    int delta = sb.getUnitIncrement(1);
+                    sb.setValue(sb.getValue() + delta);
+                  }
+              }
+            }
+    );
+    map.put("positiveBlockIncrement", 
+            new AbstractAction("positiveBlockIncrement") {
+              public void actionPerformed(ActionEvent event)
+              {
+                JScrollBar sb = (JScrollBar) event.getSource();
+                if (sb.isVisible()) 
+                  {
+                    int delta = sb.getBlockIncrement(1);
+                    sb.setValue(sb.getValue() + delta);
+                  }
+              }
+            }
+    );
+    map.put("negativeUnitIncrement", 
+            new AbstractAction("negativeUnitIncrement") {
+              public void actionPerformed(ActionEvent event)
+              {
+                JScrollBar sb = (JScrollBar) event.getSource();
+                if (sb.isVisible()) 
+                  {
+                    int delta = sb.getUnitIncrement(-1);
+                    sb.setValue(sb.getValue() + delta);
+                  }
+              }
+            }
+    );
+    map.put("negativeBlockIncrement", 
+            new AbstractAction("negativeBlockIncrement") {
+              public void actionPerformed(ActionEvent event)
+              {
+                JScrollBar sb = (JScrollBar) event.getSource();
+                if (sb.isVisible()) 
+                  {
+                    int delta = sb.getBlockIncrement(-1);
+                    sb.setValue(sb.getValue() + delta);
+                  }
+              }
+            }
+    );
+    map.put("minScroll", 
+            new AbstractAction("minScroll") {
+              public void actionPerformed(ActionEvent event)
+              {
+                JScrollBar sb = (JScrollBar) event.getSource();
+                if (sb.isVisible()) 
+                  {
+                    sb.setValue(sb.getMinimum());
+                  }
+              }
+            }
+    );
+    map.put("maxScroll", 
+            new AbstractAction("maxScroll") {
+              public void actionPerformed(ActionEvent event)
+              {
+                JScrollBar sb = (JScrollBar) event.getSource();
+                if (sb.isVisible()) 
+                  {
+                    sb.setValue(sb.getMaximum());
+                  }
+              }
+            }
+    );
+    return map;
+  }
+  
+  /**
+   * This method installs any listeners for the scrollbar. This method also
+   * installs listeners for things such as the JButtons and the timer.
+   */
+  protected void installListeners()
+  {
+    scrollListener = createScrollListener();
+    trackListener = createTrackListener();
+    buttonListener = createArrowButtonListener();
+    modelListener = createModelListener();
+    propertyChangeListener = createPropertyChangeListener();
+
+    scrollbar.addMouseMotionListener(trackListener);
+    scrollbar.addMouseListener(trackListener);
+
+    incrButton.addMouseListener(buttonListener);
+    decrButton.addMouseListener(buttonListener);
+
+    scrollbar.addPropertyChangeListener(propertyChangeListener);
+    scrollbar.getModel().addChangeListener(modelListener);
+
+    scrollTimer.addActionListener(scrollListener);
+  }
+
+  /**
+   * This method installs the UI for the component. This can include setting
+   * up listeners, defaults,  and components. This also includes initializing
+   * any data objects.
+   *
+   * @param c The JComponent to install.
+   */
+  public void installUI(JComponent c)
+  {
+    super.installUI(c);
+    if (c instanceof JScrollBar)
+      {
+        scrollbar = (JScrollBar) c;
+
+        trackRect = new Rectangle();
+        thumbRect = new Rectangle();
+
+        scrollTimer = new Timer(300, null);
+
+        installDefaults();
+        installComponents();
+        configureScrollBarColors();
+        installListeners();
+        installKeyboardActions();
+
+        calculatePreferredSize();
+      }
+  }
+
+  /**
+   * This method lays out the scrollbar.
+   *
+   * @param scrollbarContainer The Container to layout.
+   */
+  public void layoutContainer(Container scrollbarContainer)
+  {
+    if (scrollbarContainer instanceof JScrollBar)
+      {
+	if (scrollbar.getOrientation() == SwingConstants.HORIZONTAL)
+	  layoutHScrollbar((JScrollBar) scrollbarContainer);
+	else
+	  layoutVScrollbar((JScrollBar) scrollbarContainer);
+      }
+  }
+
+  /**
+   * This method lays out the scrollbar horizontally.
+   *
+   * @param sb The JScrollBar to layout.
+   */
+  protected void layoutHScrollbar(JScrollBar sb)
+  {
+    Rectangle vr = new Rectangle();
+    SwingUtilities.calculateInnerArea(scrollbar, vr);
+
+    Dimension incrDims = incrButton.getPreferredSize();
+    Dimension decrDims = decrButton.getPreferredSize();
+    
+    // calculate and update the track bounds
+    SwingUtilities.calculateInnerArea(scrollbar, trackRect);
+    trackRect.width -= incrDims.getWidth();
+    trackRect.width -= decrDims.getWidth();
+    trackRect.x += decrDims.getWidth();
+
+    updateThumbRect();
+    
+    decrButton.setBounds(vr.x, vr.y, decrDims.width, trackRect.height);
+    incrButton.setBounds(trackRect.x + trackRect.width, vr.y, incrDims.width,
+                         trackRect.height);
+  }
+
+  /**
+   * This method lays out the scrollbar vertically.
+   *
+   * @param sb The JScrollBar to layout.
+   */
+  protected void layoutVScrollbar(JScrollBar sb)
+  {
+    Rectangle vr = new Rectangle();
+    SwingUtilities.calculateInnerArea(scrollbar, vr);
+
+    Dimension incrDims = incrButton.getPreferredSize();
+    Dimension decrDims = decrButton.getPreferredSize();
+    
+    // Update rectangles
+    SwingUtilities.calculateInnerArea(scrollbar, trackRect);
+    trackRect.height -= incrDims.getHeight();
+    trackRect.height -= decrDims.getHeight();
+    trackRect.y += decrDims.getHeight();
+    
+    updateThumbRect();
+
+    decrButton.setBounds(vr.x, vr.y, trackRect.width, decrDims.height);
+    incrButton.setBounds(vr.x, trackRect.y + trackRect.height,
+                         trackRect.width, incrDims.height);
+  }
+
+  /**
+   * Updates the thumb rect.
+   */
+  void updateThumbRect()
+  {
+    int max = scrollbar.getMaximum();
+    int min = scrollbar.getMinimum();
+    int value = scrollbar.getValue();
+    int extent = scrollbar.getVisibleAmount();
+    if (max - extent <= min)
+      {
+        if (scrollbar.getOrientation() == JScrollBar.HORIZONTAL)
+          {
+            thumbRect.x = trackRect.x;
+            thumbRect.y = trackRect.y;
+            thumbRect.width = getMinimumThumbSize().width;
+            thumbRect.height = trackRect.height;
+          }
+        else
+          {
+            thumbRect.x = trackRect.x;
+            thumbRect.y = trackRect.y;
+            thumbRect.width = trackRect.width;
+            thumbRect.height = getMinimumThumbSize().height;
+          }
+      }
+    else
+      {
+        if (scrollbar.getOrientation() == JScrollBar.HORIZONTAL)
+          {
+            thumbRect.x = trackRect.x;
+            thumbRect.width = Math.max(extent * trackRect.width / (max - min),
+                getMinimumThumbSize().width);
+            int availableWidth = trackRect.width - thumbRect.width;
+            thumbRect.x += (value - min) * availableWidth / (max - min - extent);
+            thumbRect.y = trackRect.y;
+            thumbRect.height = trackRect.height;
+          }
+        else
+          {
+            thumbRect.x = trackRect.x;
+            thumbRect.height = Math.max(extent * trackRect.height / (max - min),
+                    getMinimumThumbSize().height);
+            int availableHeight = trackRect.height - thumbRect.height;
+            thumbRect.y = trackRect.y 
+              + (value - min) * availableHeight / (max - min - extent);
+            thumbRect.width = trackRect.width;
+          }
+      }
+
+  }
+  
+  /**
+   * This method returns the minimum size required for the layout.
+   *
+   * @param scrollbarContainer The Container that is laid out.
+   *
+   * @return The minimum size.
+   */
+  public Dimension minimumLayoutSize(Container scrollbarContainer)
+  {
+    return preferredLayoutSize(scrollbarContainer);
+  }
+
+  /**
+   * This method is called when the component is painted.
+   *
+   * @param g The Graphics object to paint with.
+   * @param c The JComponent to paint.
+   */
+  public void paint(Graphics g, JComponent c)
+  {
+    paintTrack(g, c, getTrackBounds());
+    paintThumb(g, c, getThumbBounds());
+
+    if (trackHighlight == INCREASE_HIGHLIGHT)
+      paintIncreaseHighlight(g);
+    else if (trackHighlight == DECREASE_HIGHLIGHT)
+      paintDecreaseHighlight(g);
+  }
+
+  /**
+   * This method is called when repainting and the mouse is  pressed in the
+   * track. It paints the track below the thumb with the trackHighlight
+   * color.
+   *
+   * @param g The Graphics object to paint with.
+   */
+  protected void paintDecreaseHighlight(Graphics g)
+  {
+    Color saved = g.getColor();
+
+    g.setColor(trackHighlightColor);
+    if (scrollbar.getOrientation() == HORIZONTAL)
+      g.fillRect(trackRect.x, trackRect.y, thumbRect.x - trackRect.x,
+                 trackRect.height);
+    else
+      g.fillRect(trackRect.x, trackRect.y, trackRect.width,
+                 thumbRect.y - trackRect.y);
+    g.setColor(saved);
+  }
+
+  /**
+   * This method is called when repainting and the mouse is  pressed in the
+   * track. It paints the track above the thumb with the trackHighlight
+   * color.
+   *
+   * @param g The Graphics objet to paint with.
+   */
+  protected void paintIncreaseHighlight(Graphics g)
+  {
+    Color saved = g.getColor();
+
+    g.setColor(trackHighlightColor);
+    if (scrollbar.getOrientation() == HORIZONTAL)
+      g.fillRect(thumbRect.x + thumbRect.width, trackRect.y,
+                 trackRect.x + trackRect.width - thumbRect.x - thumbRect.width,
+                 trackRect.height);
+    else
+      g.fillRect(trackRect.x, thumbRect.y + thumbRect.height, trackRect.width,
+                 trackRect.y + trackRect.height - thumbRect.y
+                 - thumbRect.height);
+    g.setColor(saved);
+  }
+
+  /**
+   * This method paints the thumb.
+   *
+   * @param g The Graphics object to paint with.
+   * @param c The Component that is being painted.
+   * @param thumbBounds The thumb bounds.
+   */
+  protected void paintThumb(Graphics g, JComponent c, Rectangle thumbBounds)
+  {
+    g.setColor(thumbColor);
+    g.fillRect(thumbBounds.x, thumbBounds.y, thumbBounds.width,
+               thumbBounds.height);
+
+    BasicGraphicsUtils.drawBezel(g, thumbBounds.x, thumbBounds.y,
+                                 thumbBounds.width, thumbBounds.height,
+                                 false, false, thumbDarkShadowColor,
+                                 thumbDarkShadowColor, thumbHighlightColor,
+                                 thumbHighlightColor);
+  }
+
+  /**
+   * This method paints the track.
+   *
+   * @param g The Graphics object to paint with.
+   * @param c The JComponent being painted.
+   * @param trackBounds The track's bounds.
+   */
+  protected void paintTrack(Graphics g, JComponent c, Rectangle trackBounds)
+  {
+    Color saved = g.getColor();
+    g.setColor(trackColor);
+    g.fill3DRect(trackBounds.x, trackBounds.y, trackBounds.width,
+                 trackBounds.height, false);
+    g.setColor(saved);
+  }
+
+  /**
+   * This method returns the preferred size for the layout.
+   *
+   * @param scrollbarContainer The Container to find a size for.
+   *
+   * @return The preferred size for the layout.
+   */
+  public Dimension preferredLayoutSize(Container scrollbarContainer)
+  {
+    if (scrollbarContainer instanceof JComponent)
+      return getPreferredSize((JComponent) scrollbarContainer);
+    else
+      return null;
+  }
+
+  /**
+   * This method removes a child component from the layout.
+   *
+   * @param child The child to remove.
+   */
+  public void removeLayoutComponent(Component child)
+  {
+    // You should not be removing stuff from this component.
+  }
+
+  /**
+   * The method scrolls the thumb by a block in the  direction specified.
+   *
+   * @param direction The direction to scroll.
+   */
+  protected void scrollByBlock(int direction)
+  {
+    scrollbar.setValue(scrollbar.getValue()
+                       + scrollbar.getBlockIncrement(direction));
+  }
+
+  /**
+   * The method scrolls the thumb by a unit in the direction specified.
+   *
+   * @param direction The direction to scroll.
+   */
+  protected void scrollByUnit(int direction)
+  {
+    scrollbar.setValue(scrollbar.getValue()
+                       + scrollbar.getUnitIncrement(direction));
+  }
+
+  /**
+   * This method sets the thumb's bounds.
+   *
+   * @param x The X position of the thumb.
+   * @param y The Y position of the thumb.
+   * @param width The width of the thumb.
+   * @param height The height of the thumb.
+   */
+  protected void setThumbBounds(int x, int y, int width, int height)
+  {
+    thumbRect.x = x;
+    thumbRect.y = y;
+    thumbRect.width = width;
+    thumbRect.height = height;
+  }
+
+  /**
+   * This method uninstalls any components that  are a part of or related to
+   * this scrollbar.
+   */
+  protected void uninstallComponents()
+  {
+    if (incrButton != null)
+      scrollbar.remove(incrButton);
+    if (decrButton != null)
+      scrollbar.remove(decrButton);
+  }
+
+  /**
+   * This method uninstalls any defaults that this scrollbar acquired from the
+   * Basic Look and Feel defaults.
+   */
+  protected void uninstallDefaults()
+  {
+    scrollbar.setForeground(null);
+    scrollbar.setBackground(null);
+    LookAndFeel.uninstallBorder(scrollbar);
+    incrButton = null;
+    decrButton = null;
+  }
+
+  /**
+   * This method uninstalls any listeners that were registered during install.
+   */
+  protected void uninstallListeners()
+  {
+    if (scrollTimer != null)
+      scrollTimer.removeActionListener(scrollListener);
+
+    if (scrollbar != null)
+      {
+        scrollbar.getModel().removeChangeListener(modelListener);
+        scrollbar.removePropertyChangeListener(propertyChangeListener);
+        scrollbar.removeMouseListener(trackListener);
+        scrollbar.removeMouseMotionListener(trackListener);
+      }
+
+    if (decrButton != null)
+      decrButton.removeMouseListener(buttonListener);
+    if (incrButton != null)
+      incrButton.removeMouseListener(buttonListener);
+    
+    propertyChangeListener = null;
+    modelListener = null;
+    buttonListener = null;
+    trackListener = null;
+    scrollListener = null;
+  }
+
+  /**
+   * This method uninstalls the UI. This includes removing any defaults,
+   * listeners, and components that this UI may have initialized. It also
+   * nulls any instance data.
+   *
+   * @param c The Component to uninstall for.
+   */
+  public void uninstallUI(JComponent c)
+  {
+    uninstallKeyboardActions();
+    uninstallListeners();
+    uninstallDefaults();
+    uninstallComponents();
+
+    scrollTimer = null;
+
+    thumbRect = null;
+    trackRect = null;
+
+    trackColor = null;
+    trackHighlightColor = null;
+    thumbColor = null;
+    thumbHighlightColor = null;
+    thumbDarkShadowColor = null;
+    thumbLightShadowColor = null;
+
+    scrollbar = null;
+  }
+
+  /**
+   * This method returns the value in the scrollbar's range given the y
+   * coordinate. If the value is out of range, it will return the closest
+   * legal value.
+   * This is package-private to avoid an accessor method.
+   *
+   * @param yPos The y coordinate to calculate a value for.
+   *
+   * @return The value for the y coordinate.
+   */
+  int valueForYPosition(int yPos)
+  {
+    int min = scrollbar.getMinimum();
+    int max = scrollbar.getMaximum();
+    int len = trackRect.height;
+
+    int value;
+
+    // If the length is 0, you shouldn't be able to even see where the thumb is.
+    // This really shouldn't ever happen, but just in case, we'll return the middle.
+    if (len == 0)
+      return (max - min) / 2;
+
+    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 scrollbar's range given the x
+   * coordinate. If the value is out of range, it will return the closest
+   * legal value.
+   * This is package-private to avoid an accessor method.
+   *
+   * @param xPos The x coordinate to calculate a value for.
+   *
+   * @return The value for the x coordinate.
+   */
+  int valueForXPosition(int xPos)
+  {
+    int min = scrollbar.getMinimum();
+    int max = scrollbar.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;
+
+    value = (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;
+  }
+  
+  /**
+   * Returns true if the mouse is over the thumb.
+   * 
+   * @return true if the mouse is over the thumb.
+   * 
+   * @since 1.5
+   */
+  public boolean isThumbRollover()
+  {
+   return thumbRollover; 
+  }
+  
+  /**
+   * Set thumbRollover to active. This indicates
+   * whether or not the mouse is over the thumb.
+   * 
+   * @param active - true if the mouse is over the thumb.
+   * 
+   * @since 1.5
+   */
+  protected void setThumbRollover(boolean active)
+  {
+    thumbRollover = active;
+  }
+  
+  /**
+   * Indicates whether the user can position the thumb with 
+   * a mouse click (i.e. middle button).
+   * 
+   * @return true if the user can position the thumb with a mouse
+   * click.
+   * 
+   * @since 1.5
+   */
+  public boolean getSupportsAbsolutePositioning()
+  {
+    // The positioning feature has not been implemented.
+    // So, false is always returned.
+    return false;
+  }
+}

Added: llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/BasicScrollPaneUI.java
URL: http://llvm.org/viewvc/llvm-project/llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/BasicScrollPaneUI.java?rev=43913&view=auto

==============================================================================
--- llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/BasicScrollPaneUI.java (added)
+++ llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/BasicScrollPaneUI.java Thu Nov  8 16:56:19 2007
@@ -0,0 +1,898 @@
+/* BasicScrollPaneUI.java
+   Copyright (C) 2002, 2004, 2005, 2006, Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package javax.swing.plaf.basic;
+
+import gnu.classpath.NotImplementedException;
+
+import java.awt.Component;
+import java.awt.Dimension;
+import java.awt.Graphics;
+import java.awt.Point;
+import java.awt.Rectangle;
+import java.awt.event.ActionEvent;
+import java.awt.event.ContainerEvent;
+import java.awt.event.ContainerListener;
+import java.awt.event.MouseWheelEvent;
+import java.awt.event.MouseWheelListener;
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+
+import javax.swing.AbstractAction;
+import javax.swing.Action;
+import javax.swing.ActionMap;
+import javax.swing.InputMap;
+import javax.swing.JComponent;
+import javax.swing.JScrollBar;
+import javax.swing.JScrollPane;
+import javax.swing.JSlider;
+import javax.swing.JViewport;
+import javax.swing.LookAndFeel;
+import javax.swing.ScrollPaneConstants;
+import javax.swing.ScrollPaneLayout;
+import javax.swing.Scrollable;
+import javax.swing.SwingConstants;
+import javax.swing.SwingUtilities;
+import javax.swing.UIManager;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+import javax.swing.plaf.ActionMapUIResource;
+import javax.swing.plaf.ComponentUI;
+import javax.swing.plaf.ScrollPaneUI;
+
+/**
+ * A UI delegate for the {@link JScrollPane} component.
+ */
+public class BasicScrollPaneUI extends ScrollPaneUI
+  implements ScrollPaneConstants
+{
+
+  /**
+   * Listens for changes in the state of the horizontal scrollbar's model and
+   * updates the scrollpane accordingly.
+   *
+   * @author Roman Kennke (kennke at aicas.com)
+   */
+  public class HSBChangeListener implements ChangeListener
+  {
+
+    /**
+     * Receives notification when the state of the horizontal scrollbar
+     * model has changed.
+     *
+     * @param event the change event
+     */
+    public void stateChanged(ChangeEvent event)
+    {
+      JScrollBar hsb = scrollpane.getHorizontalScrollBar();
+      JViewport vp = scrollpane.getViewport();
+      Point viewPosition = vp.getViewPosition();
+      int xpos = hsb.getValue();
+
+      if (xpos != viewPosition.x)
+        {
+          viewPosition.x = xpos;
+          vp.setViewPosition(viewPosition);
+        }
+
+      viewPosition.y = 0;
+      JViewport columnHeader = scrollpane.getColumnHeader();
+      if (columnHeader != null 
+          && !columnHeader.getViewPosition().equals(viewPosition))
+        columnHeader.setViewPosition(viewPosition);
+    }
+
+  }
+
+  /**
+   * Listens for changes in the state of the vertical scrollbar's model and
+   * updates the scrollpane accordingly.
+   *
+   * @author Roman Kennke (kennke at aicas.com)
+   */
+  public class VSBChangeListener implements ChangeListener
+  {
+
+    /**
+     * Receives notification when the state of the vertical scrollbar
+     * model has changed.
+     *
+     * @param event the change event
+     */
+    public void stateChanged(ChangeEvent event)
+    {
+      JScrollBar vsb = scrollpane.getVerticalScrollBar();
+      JViewport vp = scrollpane.getViewport();
+      Point viewPosition = vp.getViewPosition();
+      int ypos = vsb.getValue();
+      if (ypos != viewPosition.y)
+        {
+          viewPosition.y = ypos;
+          vp.setViewPosition(viewPosition);
+        }
+
+      viewPosition.x = 0;
+      JViewport rowHeader = scrollpane.getRowHeader();
+      if (rowHeader != null 
+          && !rowHeader.getViewPosition().equals(viewPosition))
+        rowHeader.setViewPosition(viewPosition);
+    }
+ 
+  }
+
+  /**
+   * Listens for changes of the viewport's extent size and updates the
+   * scrollpane accordingly.
+   *
+   * @author Roman Kennke (kennke at aicas.com)
+   */
+  public class ViewportChangeHandler implements ChangeListener
+  {
+
+    /**
+     * Receives notification when the view's size, position or extent size
+     * changes. When the extents size has changed, this method calls
+     * {@link BasicScrollPaneUI#syncScrollPaneWithViewport()} to adjust the
+     * scrollbars extents as well.
+     * 
+     * @param event the change event
+     */
+    public void stateChanged(ChangeEvent event)
+    {
+      JViewport vp = scrollpane.getViewport();
+      JScrollBar hsb = scrollpane.getHorizontalScrollBar();
+      JScrollBar vsb = scrollpane.getVerticalScrollBar();
+      syncScrollPaneWithViewport();
+    }
+
+  }
+
+  /**
+   * Listens for property changes on the scrollpane and update the view
+   * accordingly.
+   *
+   * @author Roman Kennke (kennke at aicas.com)
+   */
+  public class PropertyChangeHandler implements PropertyChangeListener
+  {
+
+    /**
+     * Receives notification when any of the scrollpane's bound property
+     * changes. This method calls the appropriate update method on the
+     * <code>ScrollBarUI</code>.
+     *
+     * @param e the property change event
+     *
+     * @see BasicScrollPaneUI#updateColumnHeader(PropertyChangeEvent)
+     * @see BasicScrollPaneUI#updateRowHeader(PropertyChangeEvent)
+     * @see BasicScrollPaneUI#updateScrollBarDisplayPolicy(PropertyChangeEvent)
+     * @see BasicScrollPaneUI#updateViewport(PropertyChangeEvent)
+     */
+    public void propertyChange(PropertyChangeEvent e)
+    {
+      String propName = e.getPropertyName();
+      if (propName.equals("viewport"))
+        updateViewport(e);
+      else if (propName.equals("rowHeader"))
+        updateRowHeader(e);
+      else if (propName.equals("columnHeader"))
+        updateColumnHeader(e);
+      else if (propName.equals("horizontalScrollBarPolicy")
+          || e.getPropertyName().equals("verticalScrollBarPolicy"))
+        updateScrollBarDisplayPolicy(e);
+      else if (propName.equals("verticalScrollBar"))
+        {
+          JScrollBar oldSb = (JScrollBar) e.getOldValue();
+          oldSb.getModel().removeChangeListener(vsbChangeListener);
+          JScrollBar newSb = (JScrollBar) e.getNewValue();
+          newSb.getModel().addChangeListener(vsbChangeListener);
+        }
+      else if (propName.equals("horizontalScrollBar"))
+        {
+          JScrollBar oldSb = (JScrollBar) e.getOldValue();
+          oldSb.getModel().removeChangeListener(hsbChangeListener);
+          JScrollBar newSb = (JScrollBar) e.getNewValue();
+          newSb.getModel().addChangeListener(hsbChangeListener);
+        }
+    }
+
+  }
+
+  /**
+   * Listens for mouse wheel events and update the scrollpane accordingly.
+   *
+   * @author Roman Kennke (kennke at aicas.com)
+   *
+   * @since 1.4
+   */
+  protected class MouseWheelHandler implements MouseWheelListener
+  {
+    /**
+     * Use to compute the visible rectangle.
+     */
+    final Rectangle rect = new Rectangle();
+
+    /**
+     * Scroll with the mouse wheel.
+     * 
+     * @author Audrius Meskauskas (audriusa at Bioinformatics.org)
+     */
+    public void mouseWheelMoved(MouseWheelEvent e)
+    {
+      if (scrollpane.getViewport().getComponentCount() == 0)
+        return;
+
+      Component target = scrollpane.getViewport().getComponent(0);
+      JScrollBar bar = scrollpane.getVerticalScrollBar();
+      Scrollable scrollable = (target instanceof Scrollable) ? (Scrollable) target
+                                                            : null;
+
+      boolean tracksHeight = scrollable != null
+                             && scrollable.getScrollableTracksViewportHeight();
+      int wheel = e.getWheelRotation() * ROWS_PER_WHEEL_CLICK;
+      int delta;
+
+      // If possible, scroll vertically.
+      if (bar != null && ! tracksHeight)
+        {
+          if (scrollable != null)
+            {
+              bounds(target);
+              delta = scrollable.getScrollableUnitIncrement(
+                rect, SwingConstants.VERTICAL, wheel);
+            }
+          else
+            {
+              // Scroll non scrollables.
+              delta = wheel * SCROLL_NON_SCROLLABLES;
+            }
+          scroll(bar, delta);
+        }
+      // If not, try to scroll horizontally
+      else
+        {
+          bar = scrollpane.getHorizontalScrollBar();
+          boolean tracksWidth = scrollable != null
+                                && scrollable.getScrollableTracksViewportWidth();
+
+          if (bar != null && ! tracksWidth)
+            {
+              if (scrollable != null)
+                {
+                  bounds(target);
+                  delta = scrollable.getScrollableUnitIncrement(
+                     rect, SwingConstants.HORIZONTAL, wheel);
+                }
+              else
+                {
+                  // Scroll non scrollables.
+                  delta = wheel * SCROLL_NON_SCROLLABLES;
+                }
+              scroll(bar, delta);
+            }
+        }
+    }
+    
+    /**
+     * Place the component bounds into rect. The x and y values 
+     * need to be reversed.
+     * 
+     * @param target the target being scrolled
+     */
+    final void bounds(Component target)
+    {
+      // Viewport bounds, translated by the scroll bar positions.
+      target.getParent().getBounds(rect);
+      rect.x = getValue(scrollpane.getHorizontalScrollBar());
+      rect.y = getValue(scrollpane.getVerticalScrollBar());
+    }
+    
+    /**
+     * Get the scroll bar value or 0 if there is no such scroll bar.
+     * 
+     * @param bar  the scroll bar (<code>null</code> permitted).
+     * 
+     * @return The scroll bar value, or 0.
+     */
+    final int getValue(JScrollBar bar)
+    {
+      return bar != null ? bar.getValue() : 0;
+    }
+    
+    /**
+     * Scroll the given distance.
+     * 
+     * @param bar the scrollbar to scroll
+     * @param delta the distance
+     */
+    final void scroll(JScrollBar bar, int delta)
+    {
+      int y = bar.getValue() + delta;
+
+      if (y < bar.getMinimum())
+        y = bar.getMinimum();
+      if (y > bar.getMaximum())
+        y = bar.getMaximum();
+
+      bar.setValue(y);
+    }
+  }
+  
+  /**
+   * Adds/removes the mouse wheel listener when the component is added/removed
+   * to/from the scroll pane view port.
+   * 
+   * @author Audrius Meskauskas (audriusa at bioinformatics.org)
+   */
+  class ViewportContainerListener implements ContainerListener
+  {
+    /**
+     * Add the mouse wheel listener, allowing to scroll with the mouse.
+     */
+    public void componentAdded(ContainerEvent e)
+    {
+      e.getChild().addMouseWheelListener(mouseWheelListener);
+    }
+    
+    /**
+     * Remove the mouse wheel listener.
+     */
+    public void componentRemoved(ContainerEvent e)
+    {
+      e.getChild().removeMouseWheelListener(mouseWheelListener);
+    }
+  }
+  
+  /**
+   * The number of pixels by that we should scroll the content that does
+   * not implement Scrollable.
+   */
+  static int SCROLL_NON_SCROLLABLES = 10;
+  
+  /**
+   * The number of rows to scroll per mouse wheel click. From impression,
+   * Sun seems using the value 3.
+   */
+  static int ROWS_PER_WHEEL_CLICK = 3;     
+
+  /** The Scrollpane for which the UI is provided by this class. */
+  protected JScrollPane scrollpane;
+
+  /**
+   * The horizontal scrollbar listener.
+   */
+  protected ChangeListener hsbChangeListener;
+
+  /**
+   * The vertical scrollbar listener.
+   */
+  protected ChangeListener vsbChangeListener;
+
+  /**
+   * The viewport listener.
+   */
+  protected ChangeListener viewportChangeListener;
+
+  /**
+   * The scrollpane property change listener.
+   */
+  protected PropertyChangeListener spPropertyChangeListener;
+
+  /**
+   * The mousewheel listener for the scrollpane.
+   */
+  MouseWheelListener mouseWheelListener;
+  
+  /**
+   * The listener to add and remove the mouse wheel listener to/from
+   * the component container.
+   */
+  ContainerListener containerListener;
+
+  public static ComponentUI createUI(final JComponent c) 
+  {
+    return new BasicScrollPaneUI();
+  }
+
+  protected void installDefaults(JScrollPane p)
+  {
+    scrollpane = p;
+    LookAndFeel.installColorsAndFont(p, "ScrollPane.background",
+                                     "ScrollPane.foreground",
+                                     "ScrollPane.font");
+    LookAndFeel.installBorder(p, "ScrollPane.border");
+    p.setOpaque(true);
+  }
+
+  protected void uninstallDefaults(JScrollPane p)
+  {
+    p.setForeground(null);
+    p.setBackground(null);
+    p.setFont(null);
+    p.setBorder(null);
+    scrollpane = null;
+  }
+    
+  public void installUI(final JComponent c) 
+  {
+    super.installUI(c);
+    installDefaults((JScrollPane) c);
+    installListeners((JScrollPane) c);
+    installKeyboardActions((JScrollPane) c);
+  }
+
+  /**
+   * Installs the listeners on the scrollbars, the viewport and the scrollpane.
+   *
+   * @param sp the scrollpane on which to install the listeners
+   */
+  protected void installListeners(JScrollPane sp)
+  {
+    if (spPropertyChangeListener == null)
+      spPropertyChangeListener = createPropertyChangeListener();
+    sp.addPropertyChangeListener(spPropertyChangeListener);
+
+    if (hsbChangeListener == null)
+      hsbChangeListener = createHSBChangeListener();
+    sp.getHorizontalScrollBar().getModel().addChangeListener(hsbChangeListener);
+    
+    if (vsbChangeListener == null)
+      vsbChangeListener = createVSBChangeListener();
+    sp.getVerticalScrollBar().getModel().addChangeListener(vsbChangeListener);
+
+    if (viewportChangeListener == null)
+      viewportChangeListener = createViewportChangeListener();
+    
+    if (mouseWheelListener == null)
+      mouseWheelListener = createMouseWheelListener();
+    
+    if (containerListener == null)
+      containerListener = new ViewportContainerListener();
+    
+    JViewport v = sp.getViewport();
+    v.addChangeListener(viewportChangeListener);
+    v.addContainerListener(containerListener);
+    
+    // Add mouse wheel listeners to the componets that are probably already
+    // in the view port.
+    for (int i = 0; i < v.getComponentCount(); i++)
+      v.getComponent(i).addMouseWheelListener(mouseWheelListener);
+  }
+
+  InputMap getInputMap(int condition) 
+  {
+    if (condition == JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT)
+      return (InputMap) UIManager.get("ScrollPane.ancestorInputMap");
+    return null;
+  }
+
+  /**
+   * Returns the action map for the {@link JScrollPane}.  All scroll panes 
+   * share a single action map which is created the first time this method is 
+   * called, then stored in the UIDefaults table for subsequent access.
+   * 
+   * @return The shared action map.
+   */
+  ActionMap getActionMap() 
+  {
+    ActionMap map = (ActionMap) UIManager.get("ScrollPane.actionMap");
+
+    if (map == null) // first time here
+      {
+        map = createActionMap();
+        if (map != null)
+          UIManager.put("ScrollPane.actionMap", map);
+      }
+    return map;
+  }
+
+  /**
+   * Creates the action map shared by all {@link JSlider} instances.
+   * This method is called once by {@link #getActionMap()} when it 
+   * finds no action map in the UIDefaults table...after the map is 
+   * created, it gets added to the defaults table so that subsequent 
+   * calls to {@link #getActionMap()} will return the same shared 
+   * instance.
+   * 
+   * @return The action map.
+   */
+  ActionMap createActionMap()
+  {
+    ActionMap map = new ActionMapUIResource();
+    map.put("scrollLeft", 
+            new AbstractAction("scrollLeft") {
+              public void actionPerformed(ActionEvent event)
+              {
+                JScrollPane sp = (JScrollPane) event.getSource();
+                JScrollBar sb = sp.getHorizontalScrollBar();
+                if (sb.isVisible()) 
+                  {
+                    int delta = sb.getBlockIncrement(-1);
+                    sb.setValue(sb.getValue() + delta);
+                  }
+              }
+            }
+    );
+    map.put("scrollEnd", 
+            new AbstractAction("scrollEnd") {
+              public void actionPerformed(ActionEvent event)
+              {
+                JScrollPane sp = (JScrollPane) event.getSource();
+                JScrollBar sb1 = sp.getHorizontalScrollBar();
+                if (sb1.isVisible()) 
+                  {
+                    sb1.setValue(sb1.getMaximum());
+                  }
+                JScrollBar sb2 = sp.getVerticalScrollBar();
+                if (sb2.isVisible()) 
+                  {
+                    sb2.setValue(sb2.getMaximum());
+                  }
+              }
+            }
+    );
+    map.put("unitScrollUp", 
+            new AbstractAction("unitScrollUp") {
+              public void actionPerformed(ActionEvent event)
+              {
+                JScrollPane sp = (JScrollPane) event.getSource();
+                JScrollBar sb = sp.getVerticalScrollBar();
+                if (sb.isVisible()) 
+                  {
+                    int delta = sb.getUnitIncrement(-1);
+                    sb.setValue(sb.getValue() + delta);
+                  }
+              }
+            }
+    );
+    map.put("unitScrollLeft", 
+            new AbstractAction("unitScrollLeft") {
+              public void actionPerformed(ActionEvent event)
+              {
+                JScrollPane sp = (JScrollPane) event.getSource();
+                JScrollBar sb = sp.getHorizontalScrollBar();
+                if (sb.isVisible()) 
+                  {
+                    int delta = sb.getUnitIncrement(-1);
+                    sb.setValue(sb.getValue() + delta);
+                  }
+              }
+            }
+    );
+    map.put("scrollUp", 
+            new AbstractAction("scrollUp") {
+              public void actionPerformed(ActionEvent event)
+              {
+                JScrollPane sp = (JScrollPane) event.getSource();
+                JScrollBar sb = sp.getVerticalScrollBar();
+                if (sb.isVisible()) 
+                  {
+                    int delta = sb.getBlockIncrement(-1);
+                    sb.setValue(sb.getValue() + delta);
+                  }
+              }
+            }
+    );
+    map.put("scrollRight", 
+            new AbstractAction("scrollRight") {
+              public void actionPerformed(ActionEvent event)
+              {
+                JScrollPane sp = (JScrollPane) event.getSource();
+                JScrollBar sb = sp.getHorizontalScrollBar();
+                if (sb.isVisible()) 
+                  {
+                    int delta = sb.getBlockIncrement(1);
+                    sb.setValue(sb.getValue() + delta);
+                  }
+              }
+            }
+    );
+    map.put("scrollHome", 
+            new AbstractAction("scrollHome") {
+              public void actionPerformed(ActionEvent event)
+              {
+                JScrollPane sp = (JScrollPane) event.getSource();
+                JScrollBar sb1 = sp.getHorizontalScrollBar();
+                if (sb1.isVisible()) 
+                  {
+                    sb1.setValue(sb1.getMinimum());
+                  }
+                JScrollBar sb2 = sp.getVerticalScrollBar();
+                if (sb2.isVisible()) 
+                  {
+                    sb2.setValue(sb2.getMinimum());
+                  }
+              }
+            }
+    );
+    map.put("scrollDown", 
+            new AbstractAction("scrollDown") {
+              public void actionPerformed(ActionEvent event)
+              {
+                JScrollPane sp = (JScrollPane) event.getSource();
+                JScrollBar sb = sp.getVerticalScrollBar();
+                if (sb.isVisible()) 
+                  {
+                    int delta = sb.getBlockIncrement(1);
+                    sb.setValue(sb.getValue() + delta);
+                  }
+              }
+            }
+    );
+    map.put("unitScrollDown", 
+            new AbstractAction("unitScrollDown") {
+              public void actionPerformed(ActionEvent event)
+              {
+                JScrollPane sp = (JScrollPane) event.getSource();
+                JScrollBar sb = sp.getVerticalScrollBar();
+                if (sb.isVisible()) 
+                  {
+                    int delta = sb.getUnitIncrement(1);
+                    sb.setValue(sb.getValue() + delta);
+                  }
+              }
+            }
+    );
+    map.put("unitScrollRight", 
+            new AbstractAction("unitScrollRight") {
+              public void actionPerformed(ActionEvent event)
+              {
+                JScrollPane sp = (JScrollPane) event.getSource();
+                JScrollBar sb = sp.getHorizontalScrollBar();
+                if (sb.isVisible()) 
+                  {
+                    int delta = sb.getUnitIncrement(1);
+                    sb.setValue(sb.getValue() + delta);
+                  }
+              }
+            }
+    );
+    return map;
+  }
+  
+  /**
+   * Installs additional keyboard actions on the scrollpane. This is a hook
+   * method provided to subclasses in order to install their own keyboard
+   * actions.
+   *
+   * @param sp the scrollpane to install keyboard actions on
+   */
+  protected void installKeyboardActions(JScrollPane sp)
+  {
+    InputMap keyMap = getInputMap(
+        JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
+    SwingUtilities.replaceUIInputMap(sp, 
+        JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT, keyMap);
+    ActionMap map = getActionMap();
+    SwingUtilities.replaceUIActionMap(sp, map);
+  }
+
+  /**
+   * Uninstalls all keyboard actions from the JScrollPane that have been
+   * installed by {@link #installKeyboardActions}. This is a hook method
+   * provided to subclasses to add their own keyboard actions.
+   *
+   * @param sp the scrollpane to uninstall keyboard actions from
+   */
+  protected void uninstallKeyboardActions(JScrollPane sp)
+  {
+    SwingUtilities.replaceUIActionMap(sp, null);
+    SwingUtilities.replaceUIInputMap(sp, 
+        JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT, null);
+  }
+  
+  /**
+   * Creates and returns the change listener for the horizontal scrollbar.
+   *
+   * @return the change listener for the horizontal scrollbar
+   */
+  protected ChangeListener createHSBChangeListener()
+  {
+    return new HSBChangeListener();
+  }
+
+  /**
+   * Creates and returns the change listener for the vertical scrollbar.
+   *
+   * @return the change listener for the vertical scrollbar
+   */
+  protected ChangeListener createVSBChangeListener()
+  {
+    return new VSBChangeListener();
+  }
+
+  /**
+   * Creates and returns the change listener for the viewport.
+   *
+   * @return the change listener for the viewport
+   */
+  protected ChangeListener createViewportChangeListener()
+  {
+    return new ViewportChangeHandler();
+  }
+
+  /**
+   * Creates and returns the property change listener for the scrollpane.
+   *
+   * @return the property change listener for the scrollpane
+   */
+  protected PropertyChangeListener createPropertyChangeListener()
+  {
+    return new PropertyChangeHandler();
+  }
+
+  /**
+   * Creates and returns the mouse wheel listener for the scrollpane.
+   *
+   * @return the mouse wheel listener for the scrollpane
+   * 
+   * @since 1.4
+   */
+  protected MouseWheelListener createMouseWheelListener()
+  {
+    return new MouseWheelHandler();
+  }
+
+  public void uninstallUI(final JComponent c) 
+  {
+    super.uninstallUI(c);
+    this.uninstallDefaults((JScrollPane) c);
+    uninstallListeners((JScrollPane) c);
+    installKeyboardActions((JScrollPane) c);
+  }
+
+  /**
+   * Uninstalls all the listeners that have been installed in
+   * {@link #installListeners(JScrollPane)}.
+   *
+   * @param c the scrollpane from which to uninstall the listeners 
+   */
+  protected void uninstallListeners(JComponent c)
+  {
+    JScrollPane sp = (JScrollPane) c;
+    sp.removePropertyChangeListener(spPropertyChangeListener);
+    sp.getHorizontalScrollBar().getModel()
+                               .removeChangeListener(hsbChangeListener);
+    sp.getVerticalScrollBar().getModel()
+                             .removeChangeListener(vsbChangeListener);
+    
+    JViewport v = sp.getViewport();
+    v.removeChangeListener(viewportChangeListener);
+    v.removeContainerListener(containerListener);
+ 
+    for (int i = 0; i < v.getComponentCount(); i++)
+      v.getComponent(i).removeMouseWheelListener(mouseWheelListener);
+
+  }
+
+  public Dimension getMinimumSize(JComponent c) 
+  {
+    JScrollPane p = (JScrollPane) c;
+    ScrollPaneLayout sl = (ScrollPaneLayout) p.getLayout();
+    return sl.minimumLayoutSize(c);
+  }
+
+  public void paint(Graphics g, JComponent c)
+  {      
+    // do nothing; the normal painting-of-children algorithm, along with
+    // ScrollPaneLayout, does all the relevant work.
+  }
+
+  /**
+   * Synchronizes the scrollbars with the viewport's extents.
+   */
+  protected void syncScrollPaneWithViewport()
+  {
+    JViewport vp = scrollpane.getViewport();
+
+    // Update the horizontal scrollbar.
+    JScrollBar hsb = scrollpane.getHorizontalScrollBar();
+    hsb.setMaximum(vp.getViewSize().width);
+    hsb.setValue(vp.getViewPosition().x);
+    hsb.setVisibleAmount(vp.getExtentSize().width);
+    
+    // Update the vertical scrollbar.
+    JScrollBar vsb = scrollpane.getVerticalScrollBar();
+    vsb.setMaximum(vp.getViewSize().height);
+    vsb.setValue(vp.getViewPosition().y);
+    vsb.setVisibleAmount(vp.getExtentSize().height);
+  }
+
+  /**
+   * Receives notification when the <code>columnHeader</code> property has
+   * changed on the scrollpane.
+   *
+   * @param ev the property change event
+   */
+  protected void updateColumnHeader(PropertyChangeEvent ev)
+  {
+    // TODO: Find out what should be done here. Or is this only a hook?
+  }
+
+  /**
+   * Receives notification when the <code>rowHeader</code> property has changed
+   * on the scrollpane.
+   *
+   * @param ev the property change event
+   */
+  protected void updateRowHeader(PropertyChangeEvent ev)
+  {
+    // TODO: Find out what should be done here. Or is this only a hook?
+  }
+
+  /**
+   * Receives notification when the <code>scrollBarDisplayPolicy</code>
+   * property has changed on the scrollpane.
+   *
+   * @param ev the property change event
+   */
+  protected void updateScrollBarDisplayPolicy(PropertyChangeEvent ev)
+  {
+    // TODO: Find out what should be done here. Or is this only a hook?
+  }
+
+  /**
+   * Receives notification when the <code>viewport</code> property has changed
+   * on the scrollpane.
+   *
+   * This method sets removes the viewportChangeListener from the old viewport
+   * and adds it to the new viewport.
+   *
+   * @param ev the property change event
+   */
+  protected void updateViewport(PropertyChangeEvent ev)
+  {
+    JViewport oldViewport = (JViewport) ev.getOldValue();
+    oldViewport.removeChangeListener(viewportChangeListener);
+    JViewport newViewport = (JViewport) ev.getNewValue();
+    newViewport.addChangeListener(viewportChangeListener);
+    syncScrollPaneWithViewport();
+  }
+}
+
+
+
+
+
+
+
+
+
+
+
+

Added: llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/BasicSeparatorUI.java
URL: http://llvm.org/viewvc/llvm-project/llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/BasicSeparatorUI.java?rev=43913&view=auto

==============================================================================
--- llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/BasicSeparatorUI.java (added)
+++ llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/BasicSeparatorUI.java Thu Nov  8 16:56:19 2007
@@ -0,0 +1,252 @@
+/* BasicSeparatorUI.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., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package javax.swing.plaf.basic;
+
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.Graphics;
+import java.awt.Rectangle;
+
+import javax.swing.JComponent;
+import javax.swing.JSeparator;
+import javax.swing.SwingUtilities;
+import javax.swing.UIManager;
+import javax.swing.plaf.ComponentUI;
+import javax.swing.plaf.SeparatorUI;
+
+/**
+ * The Basic Look and Feel UI delegate for JSeparator.
+ */
+public class BasicSeparatorUI extends SeparatorUI
+{
+  /** The shadow color. */
+  protected Color shadow;
+
+  /** The highlight color. */
+  protected Color highlight;
+
+  /**
+   * Creates a new UI delegate for the given JComponent.
+   *
+   * @param c The JComponent to create a delegate for.
+   *
+   * @return A new BasicSeparatorUI.
+   */
+  public static ComponentUI createUI(JComponent c)
+  {
+    return new BasicSeparatorUI();
+  }
+
+  /**
+   * This method installs the UI for the given JComponent.
+   * This can include installing defaults, listeners, and
+   * initializing any instance data.
+   *
+   * @param c The JComponent that is having this UI installed.
+   */
+  public void installUI(JComponent c)
+  {
+    super.installUI(c);
+
+    if (c instanceof JSeparator)
+      {
+	JSeparator s = (JSeparator) c;
+
+	installDefaults(s);
+	installListeners(s);
+      }
+  }
+
+  /**
+   * Uninstalls the UI for the given JComponent. This
+   * method reverses what was done when installing
+   * the UI on the JComponent.
+   *
+   * @param c The JComponent that is having this UI uninstalled.
+   */
+  public void uninstallUI(JComponent c)
+  {
+    if (c instanceof JSeparator)
+      {
+	JSeparator s = (JSeparator) c;
+
+	uninstallListeners(s);
+	uninstallDefaults(s);
+      }
+  }
+
+  /**
+   * This method installs the defaults that are given by
+   * the Basic Look and Feel.
+   *
+   * @param s The JSeparator that is being installed.
+   */
+  protected void installDefaults(JSeparator s)
+  {
+    shadow = UIManager.getColor("Separator.shadow");
+    highlight = UIManager.getColor("Separator.highlight");
+    s.setOpaque(false);
+  }
+
+  /**
+   * This method removes the defaults that were given
+   * by the Basic Look and Feel.
+   *
+   * @param s The JSeparator that is being uninstalled.
+   */
+  protected void uninstallDefaults(JSeparator s)
+  {
+    shadow = null;
+    highlight = null;
+  }
+
+  /**
+   * This method installs any listeners that need
+   * to be attached to the JSeparator or any of its 
+   * components.
+   *
+   * @param s The JSeparator that is being installed.
+   */
+  protected void installListeners(JSeparator s)
+  {
+    // Separators don't receive events.
+  }
+
+  /**
+   * This method uninstalls any listeners that
+   * were installed during the install UI process.
+   *
+   * @param s The JSeparator that is being uninstalled.
+   */
+  protected void uninstallListeners(JSeparator s)
+  {
+    // Separators don't receive events.  
+  }
+
+  /**
+   * The separator is made of two lines. The top line will be 
+   * the shadow color (or left line if it's vertical). The bottom 
+   * or right line will be the highlight color. The two lines will 
+   * be centered inside the bounds box. If the separator is horizontal, 
+   * then it will be vertically centered, or if it's vertical, it will 
+   * be horizontally centered.
+   *
+   * @param g The Graphics object to paint with
+   * @param c The JComponent to paint.
+   */
+  public void paint(Graphics g, JComponent c)
+  {
+    Rectangle r = new Rectangle();
+    SwingUtilities.calculateInnerArea(c, r);
+    Color saved = g.getColor();
+    
+    JSeparator s;
+    if (c instanceof JSeparator)
+      s = (JSeparator) c;
+    else
+      return;
+      
+    if (s.getOrientation() == JSeparator.HORIZONTAL)
+      {    
+        int midAB = r.height / 2;
+        g.setColor(shadow);
+        g.drawLine(r.x, r.y + midAB - 1, r.x + r.width, r.y + midAB - 1);
+
+        g.setColor(highlight);
+        g.fillRect(r.x, r.y + midAB, r.x + r.width, r.y + midAB);
+      }
+      else
+      {
+        int midAD = r.height / 2 + r.y;
+        g.setColor(shadow);
+        g.drawLine(r.x, r.y, r.x, r.y + r.height);
+
+        g.setColor(highlight);
+        g.fillRect(r.x + midAD, r.y + r.height, r.x + midAD, r.y + r.height);
+      }
+    g.setColor(saved);
+  }
+
+  /**
+   * This method returns the preferred size of the 
+   * JComponent.
+   *
+   * @param c The JComponent to measure.
+   *
+   * @return The preferred size.
+   */
+  public Dimension getPreferredSize(JComponent c)
+  {
+    Dimension pref = new Dimension(2, 0);
+    if (c instanceof JSeparator)
+      {
+	JSeparator s = (JSeparator) c;
+	if (s.getOrientation() == JSeparator.HORIZONTAL)
+          pref = new Dimension(0, 2);
+      }
+    return pref;
+  }
+
+  /**
+   * This method returns the minimum size of the
+   * JComponent.
+   *
+   * @param c The JComponent to measure.
+   *
+   * @return The minimum size.
+   */
+  public Dimension getMinimumSize(JComponent c)
+  {
+    return new Dimension(0, 0);
+  }
+
+  /**
+   * This method returns the maximum size of the
+   * JComponent.
+   *
+   * @param c The JComponent to measure.
+   *
+   * @return The maximum size.
+   */
+  public Dimension getMaximumSize(JComponent c)
+  {
+    return new Dimension(Short.MAX_VALUE,
+                         Short.MAX_VALUE);
+  }
+}

Added: llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/BasicSliderUI.java
URL: http://llvm.org/viewvc/llvm-project/llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/BasicSliderUI.java?rev=43913&view=auto

==============================================================================
--- llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/BasicSliderUI.java (added)
+++ llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/BasicSliderUI.java Thu Nov  8 16:56:19 2007
@@ -0,0 +1,2497 @@
+/* BasicSliderUI.java --
+   Copyright (C) 2004, 2005, 2006,  Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package javax.swing.plaf.basic;
+
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.ComponentOrientation;
+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.MouseEvent;
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+import java.util.Dictionary;
+import java.util.Enumeration;
+
+import javax.swing.AbstractAction;
+import javax.swing.ActionMap;
+import javax.swing.BoundedRangeModel;
+import javax.swing.InputMap;
+import javax.swing.JComponent;
+import javax.swing.JLabel;
+import javax.swing.JSlider;
+import javax.swing.LookAndFeel;
+import javax.swing.SwingUtilities;
+import javax.swing.Timer;
+import javax.swing.UIManager;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+import javax.swing.event.MouseInputAdapter;
+import javax.swing.plaf.ActionMapUIResource;
+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 contentRect and the focusRect are the FocusInsets.
+ * </p>
+ * 
+ * <p>
+ * The space between the focusRect and the component bounds is the insetCache
+ * which are the component's insets.
+ * </p>
+ * 
+ * <p>
+ * The top of the thumb is the top of the contentRect. The trackRect has to be
+ * as tall as the thumb.
+ * </p>
+ * 
+ * <p>
+ * The trackRect and tickRect do not start from the left edge of the
+ * focusRect. They are trackBuffer away from each side of the focusRect. This
+ * is so that the thumb has room to move.
+ * </p>
+ * 
+ * <p>
+ * The labelRect does start right against the contentRect'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.
+   *
+   * @specnote Apparently this class was intended to be protected,
+   *           but was made public by a compiler bug and is now
+   *           public for compatibility.
+   */
+  public 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.
+      // Only thing that needs recalculation is the thumb.
+      calculateThumbLocation();
+      slider.repaint();
+    }
+  }
+
+  /**
+   * Helper class that listens for resize events.
+   *
+   * @specnote Apparently this class was intended to be protected,
+   *           but was made public by a compiler bug and is now
+   *           public for compatibility.
+   */
+  public 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)
+    {
+      calculateGeometry();
+
+      slider.revalidate();
+      slider.repaint();
+    }
+  }
+
+  /**
+   * Helper class that listens for focus events.
+   *
+   * @specnote Apparently this class was intended to be protected,
+   *           but was made public by a compiler bug and is now
+   *           public for compatibility.
+   */
+  public 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)
+    {
+      slider.repaint();
+      hasFocus = true;
+    }
+
+    /**
+     * 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)
+    {
+      slider.repaint();
+      hasFocus = false;
+    }
+  }
+
+  /**
+   * Helper class that listens for changes to the properties of the {@link
+   * JSlider}.
+   */
+  public 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("orientation"))
+        recalculateIfOrientationChanged();
+      else if (e.getPropertyName().equals("model"))
+        {
+          BoundedRangeModel oldModel = (BoundedRangeModel) e.getOldValue();
+          oldModel.removeChangeListener(changeListener);
+          slider.getModel().addChangeListener(changeListener);
+          calculateThumbLocation();
+        }
+      else if (e.getPropertyName().equals("paintTicks"))
+        calculateGeometry();
+
+      // elif the componentOrientation changes (this is a bound property,
+      // just undocumented) we change leftToRightCache. In Sun's 
+      // implementation, the LTR cache changes on a repaint. This is strange
+      // since there is no need to do so. We could events here and 
+      // update the cache. 
+      // elif the border/insets change, we recalculateInsets.
+      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.
+   *
+   * @specnote Apparently this class was intended to be protected,
+   *           but was made public by a compiler bug and is now
+   *           public for compatibility.
+   */
+  public 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)
+    {
+      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.
+   *
+   * @specnote Apparently this class was intended to be protected,
+   *           but was made public by a compiler bug and is now
+   *           public for compatibility.
+   */
+  public class TrackListener extends MouseInputAdapter
+  {
+    /** The current X position of the mouse. */
+    protected int currentMouseX;
+
+    /** The current Y position of the mouse. */
+    protected int currentMouseY;
+
+    /**
+     * The offset between the current slider value and the cursor's position.
+     */
+    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)
+    {
+      dragging = true;
+      if (slider.isEnabled())
+        {
+          currentMouseX = e.getX();
+          currentMouseY = e.getY();
+          if (slider.getValueIsAdjusting())
+            {
+              int value;
+              if (slider.getOrientation() == JSlider.HORIZONTAL)
+                value = valueForXPosition(currentMouseX) - offset;
+              else
+                value = valueForYPosition(currentMouseY) - offset;
+
+              slider.setValue(value);
+            }
+        }
+    }
+
+    /**
+     * 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)
+    {
+      // Don't care that we're moved unless we're dragging.
+    }
+
+    /**
+     * 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)
+    {
+      if (slider.isEnabled())
+        {
+          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 the thumb is hit, then we don't need to set the timers to 
+          // move it. 
+          if (! thumbRect.contains(e.getPoint()))
+            {
+              // 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);
+            }
+          else
+            {
+              slider.setValueIsAdjusting(true);
+              offset = value - slider.getValue();
+            }
+        }
+    }
+
+    /**
+     * 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)
+    {
+      dragging = false;
+      if (slider.isEnabled())
+        {
+          currentMouseX = e.getX();
+          currentMouseY = e.getY();
+
+          if (slider.getValueIsAdjusting())
+            {
+              slider.setValueIsAdjusting(false);
+              if (slider.getSnapToTicks())
+                slider.setValue(findClosestTick(slider.getValue()));
+            }
+          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();
+    }
+  }
+
+  /**
+   * This class is no longer used as of JDK1.3.
+   */
+  public class ActionScroller extends AbstractAction
+  {
+    /**
+     * Not used.
+     *
+     * @param slider not used
+     * @param dir not used
+     * @param block not used
+     */
+    public ActionScroller(JSlider slider, int dir, boolean block)
+    {
+      // Not used.
+    }
+
+    /**
+     * Not used.
+     *
+     * @param event not used
+     */
+    public void actionPerformed(ActionEvent event)
+    {
+      // Not used.
+    }
+  }
+
+  /** 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;
+
+  /** Whether this slider is actually drawn left to right. */
+  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;
+  
+  /** True if the slider has focus. */
+  private transient boolean hasFocus;
+  
+  /** True if the user is dragging the slider. */
+  boolean dragging;
+
+  /**
+   * 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();
+  }
+
+  /**
+   * Returns true if the user is dragging the slider.
+   * 
+   * @return true if the slider is being dragged.
+   * 
+   * @since 1.5
+   */
+  protected boolean isDragging()
+  {
+    return dragging;
+  }
+  
+  /**
+   * 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(200, null);
+        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)
+  {
+    LookAndFeel.installColors(slider, "Slider.background",
+                              "Slider.foreground");
+    LookAndFeel.installBorder(slider, "Slider.border");
+    shadowColor = UIManager.getColor("Slider.shadow");
+    highlightColor = UIManager.getColor("Slider.highlight");
+    focusColor = UIManager.getColor("Slider.focus");
+    focusInsets = UIManager.getInsets("Slider.focusInsets");
+    slider.setOpaque(true);
+  }
+
+  /**
+   * 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)
+  {
+    InputMap keyMap = getInputMap(JComponent.WHEN_FOCUSED);
+    SwingUtilities.replaceUIInputMap(slider, JComponent.WHEN_FOCUSED, keyMap);
+    ActionMap map = getActionMap();
+    SwingUtilities.replaceUIActionMap(slider, map);
+  }
+
+  /**
+   * 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)
+  {
+    SwingUtilities.replaceUIActionMap(slider, null);
+    SwingUtilities.replaceUIInputMap(slider, JComponent.WHEN_FOCUSED, null);
+  }
+
+  /* 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 size when the slider is horizontally
+   * oriented.
+   *
+   * @return The dimensions of the preferred horizontal size.
+   */
+  public Dimension getPreferredHorizontalSize()
+  {
+    Insets insets = slider.getInsets();
+
+    // The width should cover all the labels (which are usually the
+    // deciding factor of the width)
+    int width = getWidthOfWidestLabel() * (slider.getLabelTable() == null ? 0
+        : slider.getLabelTable().size());
+
+    // If there are not enough labels.
+    // This number is pretty much arbitrary, but it looks nice.
+    if (width < 200)
+      width = 200;
+
+    // We can only draw inside of the focusRectangle, so we have to
+    // pad it with insets.
+    width += insets.left + insets.right + focusInsets.left + focusInsets.right;
+
+    // Height is determined by the thumb, the ticks and the labels.
+    int height = getThumbSize().height;
+
+    if (slider.getPaintTicks() && slider.getMajorTickSpacing() > 0
+        || slider.getMinorTickSpacing() > 0)
+      height += getTickLength();
+
+    if (slider.getPaintLabels())
+      height += getHeightOfTallestLabel();
+
+    height += insets.top + insets.bottom + focusInsets.top
+    + focusInsets.bottom;
+
+    return new Dimension(width, height);
+  }
+
+  /**
+   * This method returns the preferred size when the slider is vertically
+   * oriented.
+   *
+   * @return The dimensions of the preferred vertical size.
+   */
+  public Dimension getPreferredVerticalSize()
+  {
+    Insets insets = slider.getInsets();
+
+    int height = getHeightOfTallestLabel() * (slider.getLabelTable() == null
+                                              ? 0 : slider.getLabelTable()
+                                                          .size());
+
+    if (height < 200)
+      height = 200;
+
+    height += insets.top + insets.bottom + focusInsets.top
+    + focusInsets.bottom;
+
+    int width = getThumbSize().width;
+
+    if (slider.getPaintTicks() && slider.getMajorTickSpacing() > 0
+        || slider.getMinorTickSpacing() > 0)
+      width += getTickLength();
+
+    if (slider.getPaintLabels())
+      width += getWidthOfWidestLabel();
+
+    width += insets.left + insets.right + focusInsets.left + focusInsets.right;
+
+    return new Dimension(width, height);
+  }
+
+  /**
+   * This method returns the minimum size when the slider is horizontally
+   * oriented.
+   *
+   * @return The dimensions of the minimum horizontal size.
+   */
+  public Dimension getMinimumHorizontalSize()
+  {
+    Insets insets = slider.getInsets();
+    // Height is determined by the thumb, the ticks and the labels.
+    int height = getThumbSize().height; 
+
+    if (slider.getPaintTicks() && slider.getMajorTickSpacing() > 0
+        || slider.getMinorTickSpacing() > 0)
+      height += getTickLength();
+
+    if (slider.getPaintLabels())
+      height += getHeightOfTallestLabel();
+
+    height += insets.top + insets.bottom + focusInsets.top
+        + focusInsets.bottom;
+
+    return new Dimension(36, height);
+  }
+
+  /**
+   * This method returns the minimum size of the slider when it  is vertically
+   * oriented.
+   *
+   * @return The dimensions of the minimum vertical size.
+   */
+  public Dimension getMinimumVerticalSize()
+  {
+    Insets insets = slider.getInsets();
+    int width = getThumbSize().width;
+
+    if (slider.getPaintTicks() && slider.getMajorTickSpacing() > 0
+        || slider.getMinorTickSpacing() > 0)
+      width += getTickLength();
+
+    if (slider.getPaintLabels())
+      width += getWidthOfWidestLabel();
+
+    width += insets.left + insets.right + focusInsets.left + focusInsets.right;
+
+    return new Dimension(width, 36);
+  }
+
+  /**
+   * 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)
+  {
+    if (slider.getOrientation() == JSlider.HORIZONTAL)
+      return getPreferredHorizontalSize();
+    else
+      return getPreferredVerticalSize();
+  }
+
+  /**
+   * 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)
+  {
+    if (slider.getOrientation() == JSlider.HORIZONTAL)
+      return getMinimumHorizontalSize();
+    else
+      return getMinimumVerticalSize();
+  }
+
+  /**
+   * This method returns the maximum size for this {@link JSlider} for this
+   * look and feel.
+   *
+   * @param c The {@link JComponent} to find a maximum size for.
+   *
+   * @return The dimensions of the maximum size.
+   */
+  public Dimension getMaximumSize(JComponent c)
+  {
+    Insets insets = slider.getInsets();
+    if (slider.getOrientation() == JSlider.HORIZONTAL)
+      {
+        // Height is determined by the thumb, the ticks and the labels.
+        int height = getThumbSize().height; 
+
+        if (slider.getPaintTicks() && slider.getMajorTickSpacing() > 0
+            || slider.getMinorTickSpacing() > 0)
+          height += getTickLength();
+
+        if (slider.getPaintLabels())
+          height += getHeightOfTallestLabel();
+
+        height += insets.top + insets.bottom + focusInsets.top
+            + focusInsets.bottom;
+
+        return new Dimension(32767, height);
+      }
+    else
+      {
+        int width = getThumbSize().width;
+
+        if (slider.getPaintTicks() && slider.getMajorTickSpacing() > 0
+            || slider.getMinorTickSpacing() > 0)
+          width += getTickLength();
+
+        if (slider.getPaintLabels())
+          width += getWidthOfWidestLabel();
+
+        width += insets.left + insets.right + focusInsets.left 
+            + focusInsets.right;
+
+        return new Dimension(width, 32767);
+      }
+  }
+
+  /**
+   * This method calculates all the sizes of the rectangles by delegating to
+   * the helper methods calculateXXXRect.
+   */
+  protected void calculateGeometry()
+  {
+    calculateFocusRect();
+    calculateContentRect();
+    calculateThumbSize();
+    calculateTrackBuffer();
+    calculateTrackRect();
+    calculateTickRect();
+    calculateLabelRect();
+    calculateThumbLocation();
+  }
+
+  /**
+   * This method calculates the size and position of the focusRect. This
+   * method does not need to be called if the orientation changes.
+   */
+  protected void calculateFocusRect()
+  {
+    insetCache = slider.getInsets();
+    focusRect = SwingUtilities.calculateInnerArea(slider, focusRect);
+    if (focusRect.width < 0)
+      focusRect.width = 0;
+    if (focusRect.height < 0)
+      focusRect.height = 0;
+  }
+
+  /**
+   * Sets the width and height of the <code>thumbRect</code> field, using the
+   * dimensions returned by {@link #getThumbSize()}.
+   */
+  protected void calculateThumbSize()
+  {
+    Dimension d = getThumbSize();
+    thumbRect.width = d.width;
+    thumbRect.height = d.height;
+  }
+
+  /**
+   * Updates the <code>contentRect</code> field to an area inside the 
+   * <code>focusRect</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 thumbRect 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 = trackRect.y + 1;
+      }
+    else
+      {
+        thumbRect.x = trackRect.x + 1;
+        thumbRect.y = yPositionForValue(value) - thumbRect.height / 2;
+      }
+  }
+
+  /**
+   * Calculates the gap size between the edge of the <code>contentRect</code> 
+   * and the edge of the <code>trackRect</code>, storing the result in the
+   * <code>trackBuffer</code> field.  Sufficient space needs to be reserved 
+   * for the slider thumb and/or the labels at each end of the slider track.
+   */
+  protected void calculateTrackBuffer()
+  {
+    if (slider.getOrientation() == JSlider.HORIZONTAL)
+      {
+        int w = Math.max(getWidthOfLowValueLabel(), getWidthOfHighValueLabel());
+        trackBuffer = Math.max(thumbRect.width / 2, w / 2);
+        
+      }
+    else
+      {
+        int h = Math.max(getHeightOfLowValueLabel(), 
+                         getHeightOfHighValueLabel());
+        trackBuffer = Math.max(thumbRect.height / 2, h / 2);
+      }
+  }
+
+  /**
+   * Returns the size of the slider's thumb.  The size is hard coded to
+   * <code>11 x 20</code> for horizontal sliders, and <code>20 x 11</code> for 
+   * vertical sliders. Note that a new instance of {@link Dimension} is 
+   * returned for every call to this method (this seems wasteful, but 
+   * {@link Dimension} instances are not immutable, so this is probably 
+   * unavoidable).
+   *
+   * @return The size of the slider's thumb.
+   */
+  protected Dimension getThumbSize()
+  {
+    if (slider.getOrientation() == JSlider.HORIZONTAL)
+      return new Dimension(11, 20);
+    else
+      return new Dimension(20, 11);
+  }
+
+  /**
+   * Calculates the size and position of the trackRect. It must take into
+   * account the orientation of the slider.
+   */
+  protected void calculateTrackRect()
+  {
+    if (slider.getOrientation() == JSlider.HORIZONTAL)
+      {
+        trackRect.x = contentRect.x + trackBuffer;
+        int h = getThumbSize().height;
+        if (slider.getPaintTicks() && (slider.getMajorTickSpacing() > 0 
+            || slider.getMinorTickSpacing() > 0))
+          h += getTickLength();
+        if (slider.getPaintLabels())
+          h += getHeightOfTallestLabel();
+        trackRect.y = contentRect.y + (contentRect.height - h) / 2 - 1;
+        trackRect.width = contentRect.width - 2 * trackBuffer;
+        trackRect.height = thumbRect.height;
+      }
+    else
+      {
+        int w = getThumbSize().width;
+        if (slider.getPaintTicks() && (slider.getMajorTickSpacing() > 0
+            || slider.getMinorTickSpacing() > 0))
+          w += getTickLength();  
+        if (slider.getPaintLabels())
+          w += getWidthOfWidestLabel();
+        trackRect.x = contentRect.x + (contentRect.width - w) / 2 - 1;
+        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 8;
+  }
+
+  /**
+   * This method calculates the size and position of the tickRect. 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 = slider.getPaintTicks() ? getTickLength() : 0;
+        
+        // this makes our Mauve tests pass...can't explain it!
+        if (!slider.getPaintTicks())
+          tickRect.y--;
+
+        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 = slider.getPaintTicks() ? getTickLength() : 0;
+        tickRect.height = trackRect.height;
+
+        // this makes our Mauve tests pass...can't explain it!
+        if (!slider.getPaintTicks())
+          tickRect.x--;
+
+        if (tickRect.x + tickRect.width > contentRect.x + contentRect.width)
+          tickRect.width = contentRect.x + contentRect.width - tickRect.x;
+      }
+  }
+
+  /**
+   * Calculates the <code>labelRect</code> field, taking into account the 
+   * orientation of the slider.
+   */
+  protected void calculateLabelRect()
+  {
+    if (slider.getOrientation() == JSlider.HORIZONTAL)
+      {
+        if (slider.getPaintLabels())
+          {
+            labelRect.x = contentRect.x;
+            labelRect.y = tickRect.y + tickRect.height - 1;
+            labelRect.width = contentRect.width;
+          }
+        else
+          {
+            labelRect.x = trackRect.x;
+            labelRect.y = tickRect.y + tickRect.height;
+            labelRect.width = trackRect.width;
+          }
+        labelRect.height = getHeightOfTallestLabel();
+      }
+    else
+      {
+        if (slider.getPaintLabels())
+          {
+            labelRect.x = tickRect.x + tickRect.width - 1;
+            labelRect.y = contentRect.y;
+            labelRect.height = contentRect.height;
+          }
+        else
+          {
+            labelRect.x = tickRect.x + tickRect.width;
+            labelRect.y = trackRect.y;
+            labelRect.height = trackRect.height;
+          }
+        labelRect.width = getWidthOfWidestLabel();
+      }
+  }
+
+  /**
+   * 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;
+
+    Dimension pref;
+    for (Enumeration list = slider.getLabelTable().elements();
+         list.hasMoreElements();)
+      {
+        Object comp = list.nextElement();
+        if (! (comp instanceof Component))
+          continue;
+        label = (Component) comp;
+        pref = label.getPreferredSize();
+        if (pref != null && pref.width > widest)
+          widest = pref.width;
+      }
+    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;
+    Dimension pref;
+    for (Enumeration list = slider.getLabelTable().elements();
+         list.hasMoreElements();)
+      {
+        Object comp = list.nextElement();
+        if (! (comp instanceof Component))
+          continue;
+        label = (Component) comp;
+        pref = label.getPreferredSize();
+        if (pref != null && pref.height > tallest)
+          tallest = pref.height;
+      }
+    return tallest;
+  }
+
+  /**
+   * Returns the width of the label whose key has the highest value, or 0 if
+   * there are no labels.
+   *
+   * @return The width of the label whose key has the highest value.
+   * 
+   * @see #getHighestValueLabel()
+   */
+  protected int getWidthOfHighValueLabel()
+  {
+    Component highValueLabel = getHighestValueLabel();
+    if (highValueLabel != null)
+      return highValueLabel.getPreferredSize().width;
+    else
+      return 0;
+  }
+
+  /**
+   * Returns the width of the label whose key has the lowest value, or 0 if
+   * there are no labels.
+   *
+   * @return The width of the label whose key has the lowest value.
+   * 
+   * @see #getLowestValueLabel()
+   */
+  protected int getWidthOfLowValueLabel()
+  {
+    Component lowValueLabel = getLowestValueLabel();
+    if (lowValueLabel != null)
+      return lowValueLabel.getPreferredSize().width;
+    else
+      return 0;
+  }
+
+  /**
+   * Returns the height of the label whose key has the highest value, or 0 if
+   * there are no labels.
+   *
+   * @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.getPreferredSize().height;
+    else
+      return 0;
+  }
+
+  /**
+   * Returns the height of the label whose key has the lowest value, or 0 if
+   * there are no labels.
+   *
+   * @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.getPreferredSize().height;
+    else
+      return 0;
+  }
+
+  /**
+   * Returns <code>true</code> if the slider scale is to be drawn inverted,
+   * and <code>false</code> if not.
+   *
+   * @return <code>true</code> if the slider is to be drawn inverted.
+   */
+  protected boolean drawInverted()
+  {
+    return slider.getInverted();
+  }
+
+  /**
+   * 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;
+  }
+
+  /**
+   * Returns the label whose key has the highest value.
+   *
+   * @return The label whose key has the highest value or <code>null</code> 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: Move this to propertyChangeEvent handler, when we get those.
+    leftToRightCache = slider.getComponentOrientation() 
+        != ComponentOrientation.RIGHT_TO_LEFT;
+    // FIXME: This next line is only here because the above line is here.
+    calculateGeometry();
+
+    if (slider.getPaintTrack())
+      paintTrack(g);
+    if (slider.getPaintTicks())
+      paintTicks(g);
+    if (slider.getPaintLabels())
+      paintLabels(g);
+    
+    paintThumb(g);
+    
+    if (hasFocus)
+      paintFocus(g);
+  }
+
+  /**
+   * This method recalculates any rectangles that need to be recalculated
+   * after the insets of the component have changed.
+   */
+  protected void recalculateIfInsetsChanged()
+  {
+    // Examining a test program shows that either Sun calls private
+    // methods that we don't know about, or these don't do anything.
+    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()
+  {
+    // Examining a test program shows that either Sun calls private
+    // methods that we don't know about, or these don't do anything.  
+    calculateThumbSize();
+    calculateTrackBuffer();
+    calculateTrackRect();
+    calculateThumbLocation();
+
+    calculateTickRect();
+    calculateLabelRect();
+  }
+
+  /**
+   * This method is called during a repaint if the slider has focus. It draws
+   * an outline of the  focusRect 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 trackRect. 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.
+   * </p>
+   *
+   * @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 + 1);
+    Point b = new Point(a);
+    Point c = new Point(a);
+    Point d = new Point(a);
+
+    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);
+      }
+    g.setColor(Color.GRAY);
+    g.fillRect(a.x, a.y, width, height);
+
+    g.setColor(getHighlightColor());
+    g.drawLine(b.x, b.y, c.x, c.y);
+    g.drawLine(c.x, c.y, d.x, d.y);
+
+    g.setColor(getShadowColor());
+    g.drawLine(b.x, b.y, a.x, a.y);
+    g.drawLine(a.x, a.y, d.x, d.y);
+
+    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)
+          {
+            g.translate(0, tickRect.y);
+            for (int i = min; i <= max; i += majorSpace)
+              paintMajorTickForHorizSlider(g, tickRect, xPositionForValue(i));
+            g.translate(0, -tickRect.y);
+          }
+        else // JSlider.VERTICAL
+          {
+            g.translate(tickRect.x, 0);
+            for (int i = min; i <= max; i += majorSpace)
+              paintMajorTickForVertSlider(g, tickRect, yPositionForValue(i));
+            g.translate(-tickRect.x, 0);
+          }
+      }
+    if (minorSpace > 0)
+      {
+        if (slider.getOrientation() == JSlider.HORIZONTAL)
+          {
+            g.translate(0, tickRect.y);
+            for (int i = min; i <= max; i += minorSpace)
+              paintMinorTickForHorizSlider(g, tickRect, xPositionForValue(i));
+            g.translate(0, -tickRect.y);
+          }
+        else
+          {
+            g.translate(tickRect.x, 0);
+            for (int i = min; i <= max; i += minorSpace)
+              paintMinorTickForVertSlider(g, tickRect, yPositionForValue(i));
+            g.translate(-tickRect.x, 0);
+          }
+      }
+  }
+
+  /* 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 x
+   * value. x represents the x coordinate to paint at.
+   *
+   * @param g The {@link Graphics} object to draw with.
+   * @param tickBounds The tickRect rectangle.
+   * @param x The x coordinate to draw the tick at.
+   */
+  protected void paintMinorTickForHorizSlider(Graphics g,
+                                              Rectangle tickBounds, int x)
+  {
+    int y = tickRect.height / 4;
+    Color saved = g.getColor();
+    g.setColor(Color.BLACK);
+
+    g.drawLine(x, y, x, y + tickRect.height / 4);
+    g.setColor(saved);
+  }
+
+  /**
+   * This method paints a major tick for a horizontal slider at the given x
+   * value. x represents the x coordinate to paint at.
+   *
+   * @param g The {@link Graphics} object to draw with.
+   * @param tickBounds The tickRect rectangle.
+   * @param x The x coordinate to draw the tick at.
+   */
+  protected void paintMajorTickForHorizSlider(Graphics g,
+                                              Rectangle tickBounds, int x)
+  {
+    int y = tickRect.height / 4;
+    Color saved = g.getColor();
+    g.setColor(Color.BLACK);
+
+    g.drawLine(x, y, x, y + tickRect.height / 2);
+    g.setColor(saved);
+  }
+
+  /**
+   * This method paints a minor tick for a vertical slider at the given y
+   * value. y represents the y coordinate to paint at.
+   *
+   * @param g The {@link Graphics} object to draw with.
+   * @param tickBounds The tickRect rectangle.
+   * @param y The y coordinate to draw the tick at.
+   */
+  protected void paintMinorTickForVertSlider(Graphics g, Rectangle tickBounds,
+                                             int y)
+  {
+    int x = tickRect.width / 4;
+    Color saved = g.getColor();
+    g.setColor(Color.BLACK);
+
+    g.drawLine(x, y, x + tickRect.width / 4, y);
+    g.setColor(saved);
+  }
+
+  /**
+   * This method paints a major tick for a vertical slider at the given y
+   * value. y represents the y coordinate to paint at.
+   *
+   * @param g The {@link Graphics} object to draw with.
+   * @param tickBounds The tickRect rectangle.
+   * @param y The y coordinate to draw the tick at.
+   */
+  protected void paintMajorTickForVertSlider(Graphics g, Rectangle tickBounds,
+                                             int y)
+  {
+    int x = tickRect.width / 4;
+    Color saved = g.getColor();
+    g.setColor(Color.BLACK);
+
+    g.drawLine(x, y, x + tickRect.width / 2, y);
+    g.setColor(saved);
+  }
+
+  /**
+   * 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;
+        Object 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 labelRect.
+   *
+   * @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)
+  {
+    // This relies on clipping working properly or we'll end up
+    // painting all over the place. If our preferred size is ignored, then
+    // the labels may not fit inside the slider's bounds. Rather than mucking 
+    // with font sizes and possible icon sizes, we'll set the bounds for
+    // the label and let it get clipped.
+    Dimension dim = label.getPreferredSize();
+    int w = (int) dim.getWidth();
+    int h = (int) dim.getHeight();
+
+    int max = slider.getMaximum();
+    int min = slider.getMinimum();
+
+    if (value > max || value < min)
+      return;
+
+    //           value
+    //             |
+    //        ------------
+    //        |          |
+    //        |          |
+    //        |          |
+    //  The label must move w/2 to the right to fit directly under the value.
+    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);
+    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 labelRect.
+   *
+   * @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)
+  {
+    Dimension dim = label.getPreferredSize();
+    int w = (int) dim.getWidth();
+    int h = (int) dim.getHeight();
+
+    int max = slider.getMaximum();
+    int min = slider.getMinimum();
+
+    if (value > max || value < min)
+      return;
+
+    int xpos = labelRect.x;
+    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);
+    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();
+
+    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 light; // light shadow
+    Polygon dark; // dark shadow
+    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 - 1, 0);
+        c.translate(thumbRect.width - 1, turnPoint);
+        d.translate(thumbRect.width / 2 - 1, thumbRect.height - 1);
+        e.translate(0, turnPoint);
+
+        bright = new Polygon(new int[] { b.x - 1, 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 + 1 }, new int[] { b.y,
+                                                                       c.y - 1,
+                                                                       d.y }, 3);
+
+        light = new Polygon(new int[] { b.x - 1, c.x - 1, d.x + 1 },
+                            new int[] { b.y + 1, c.y - 1, d.y - 1 }, 3);
+
+        all = new Polygon(
+                          new int[] { a.x + 1, b.x - 2, c.x - 2, d.x, e.x + 1 },
+                          new int[] { a.y + 1, b.y + 1, c.y - 1, d.y - 1, e.y },
+                          5);
+      }
+    else
+      {
+        turnPoint = thumbRect.width * 3 / 4 - 1;
+
+        b.translate(turnPoint, 0);
+        c.translate(thumbRect.width - 1, thumbRect.height / 2);
+        d.translate(turnPoint, thumbRect.height - 1);
+        e.translate(0, thumbRect.height - 1);
+
+        bright = new Polygon(new int[] { c.x - 1, b.x, a.x, e.x },
+                             new int[] { c.y - 1, b.y, a.y, e.y - 1 }, 4);
+
+        dark = new Polygon(new int[] { c.x, d.x, e.x }, new int[] { c.y, d.y,
+                                                                   e.y }, 3);
+
+        light = new Polygon(new int[] { c.x - 1, d.x, e.x + 1 },
+                            new int[] { c.y, d.y - 1, e.y - 1 }, 3);
+        all = new Polygon(new int[] { a.x + 1, b.x, c.x - 2, c.x - 2, d.x,
+                                     e.x + 1 }, new int[] { a.y + 1, b.y + 1,
+                                                           c.y - 1, c.y,
+                                                           d.y - 2, e.y - 2 },
+                          6);
+      }
+
+    g.setColor(Color.WHITE);
+    g.drawPolyline(bright.xpoints, bright.ypoints, bright.npoints);
+
+    g.setColor(Color.BLACK);
+    g.drawPolyline(dark.xpoints, dark.ypoints, dark.npoints);
+
+    g.setColor(Color.GRAY);
+    g.drawPolyline(light.xpoints, light.ypoints, light.npoints);
+
+    g.setColor(Color.LIGHT_GRAY);
+    g.drawPolyline(all.xpoints, all.ypoints, all.npoints);
+    g.fillPolygon(all);
+
+    g.setColor(saved_color);
+  }
+
+  /**
+   * This method sets the position of the thumbRect.
+   *
+   * @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;
+  }
+
+  /**
+   * Moves the thumb one block in the direction specified (a block is 1/10th
+   * of the slider range).   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 (positive values increment the thumb 
+   *   position by one block, zero/negative values decrement the thumb position
+   *   by one block).
+   */
+  public void scrollByBlock(int direction)
+  {
+    int unit = (slider.getMaximum() - slider.getMinimum()) / 10;
+    int moveTo = slider.getValue();
+    if (direction > 0)
+      moveTo += unit;
+    else
+      moveTo -= unit;
+
+    if (slider.getSnapToTicks())
+      moveTo = findClosestTick(moveTo);
+
+    slider.setValue(moveTo);
+  }
+
+  /**
+   * Moves the thumb one unit in the specified direction. 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 (positive values increment the thumb 
+   *   position by one, zero/negative values decrement the thumb position by
+   *   one).
+   */
+  public void scrollByUnit(int direction)
+  {
+    int moveTo = slider.getValue();
+    if (direction > 0)
+      moveTo++;
+    else
+      moveTo--;
+
+    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)
+  {
+    scrollTimer.stop();
+
+    scrollListener.setDirection(dir);
+    scrollListener.setScrollByBlock(true);
+
+    scrollTimer.start();
+  }
+
+  /**
+   * Returns the x-coordinate (relative to the component) for the given slider 
+   * value.  This method assumes that the <code>trackRect</code> field is
+   * set up.
+   *
+   * @param value  the slider value.
+   *
+   * @return The x-coordinate.
+   */
+  protected int xPositionForValue(int value)
+  {
+    double min = slider.getMinimum();
+    if (value < min)
+      value = (int) min;
+    double max = slider.getMaximum();
+    if (value > max)
+      value = (int) max;
+    double len = trackRect.width;
+    if ((max - min) <= 0.0)
+      return 0;
+    int xPos = (int) ((value - min) / (max - min) * len + 0.5);
+
+    if (drawInverted())
+      return trackRect.x + Math.max(trackRect.width - xPos - 1, 0);
+    else
+      return trackRect.x + Math.min(xPos, trackRect.width - 1);
+  }
+
+  /**
+   * Returns the y-coordinate (relative to the component) for the given slider 
+   * value.  This method assumes that the <code>trackRect</code> field is 
+   * set up.
+   *
+   * @param value  the slider value.
+   *
+   * @return The y-coordinate.
+   */
+  protected int yPositionForValue(int value)
+  {
+    double min = slider.getMinimum();
+    if (value < min)
+      value = (int) min;
+    double max = slider.getMaximum();
+    if (value > max)
+      value = (int) max;
+    int len = trackRect.height;
+    if ((max - min) <= 0.0)
+      return 0;
+
+    int yPos = (int) ((value - min) / (max - min) * len + 0.5);
+
+    if (! drawInverted())
+      return trackRect.y + trackRect.height - Math.max(yPos, 1);
+    else
+      return trackRect.y + Math.min(yPos, trackRect.height - 1);
+  }
+
+  /**
+   * 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.
+   * This is package-private to avoid an accessor method.
+   *
+   * @param value The value to search from.
+   *
+   * @return The closest value that has a tick associated with it.
+   */
+  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;
+  }
+  
+  InputMap getInputMap(int condition) 
+  {
+    if (condition == JComponent.WHEN_FOCUSED)
+      return (InputMap) UIManager.get("Slider.focusInputMap");
+    return null;
+  }
+
+  /**
+   * Returns the action map for the {@link JSlider}.  All sliders share
+   * a single action map which is created the first time this method is 
+   * called, then stored in the UIDefaults table for subsequent access.
+   * 
+   * @return The shared action map.
+   */
+  ActionMap getActionMap() 
+  {
+    ActionMap map = (ActionMap) UIManager.get("Slider.actionMap");
+
+    if (map == null) // first time here
+      {
+        map = createActionMap();
+        if (map != null)
+          UIManager.put("Slider.actionMap", map);
+      }
+    return map;
+  }
+
+  /**
+   * Creates the action map shared by all {@link JSlider} instances.
+   * This method is called once by {@link #getActionMap()} when it 
+   * finds no action map in the UIDefaults table...after the map is 
+   * created, it gets added to the defaults table so that subsequent 
+   * calls to {@link #getActionMap()} will return the same shared 
+   * instance.
+   * 
+   * @return The action map.
+   */
+  ActionMap createActionMap()
+  {
+    ActionMap map = new ActionMapUIResource();
+    map.put("positiveUnitIncrement", 
+            new AbstractAction("positiveUnitIncrement") {
+              public void actionPerformed(ActionEvent event)
+              {
+                JSlider slider = (JSlider) event.getSource();
+                BasicSliderUI ui = (BasicSliderUI) slider.getUI();
+                if (slider.getInverted())
+                  ui.scrollByUnit(BasicSliderUI.NEGATIVE_SCROLL);
+                else
+                  ui.scrollByUnit(BasicSliderUI.POSITIVE_SCROLL);
+              }
+            }
+    );
+    map.put("negativeUnitIncrement", 
+            new AbstractAction("negativeUnitIncrement") {
+              public void actionPerformed(ActionEvent event)
+              {
+                JSlider slider = (JSlider) event.getSource();
+                BasicSliderUI ui = (BasicSliderUI) slider.getUI();
+                if (slider.getInverted())
+                  ui.scrollByUnit(BasicSliderUI.POSITIVE_SCROLL);
+                else
+                  ui.scrollByUnit(BasicSliderUI.NEGATIVE_SCROLL);
+              }
+            }
+    );
+    map.put("positiveBlockIncrement", 
+            new AbstractAction("positiveBlockIncrement") {
+              public void actionPerformed(ActionEvent event)
+              {
+                JSlider slider = (JSlider) event.getSource();
+                BasicSliderUI ui = (BasicSliderUI) slider.getUI();
+                if (slider.getInverted())
+                  ui.scrollByBlock(BasicSliderUI.NEGATIVE_SCROLL);
+                else
+                  ui.scrollByBlock(BasicSliderUI.POSITIVE_SCROLL);
+              }
+            }
+    );
+    map.put("negativeBlockIncrement", 
+            new AbstractAction("negativeBlockIncrement") {
+              public void actionPerformed(ActionEvent event)
+              {
+                JSlider slider = (JSlider) event.getSource();
+                BasicSliderUI ui = (BasicSliderUI) slider.getUI();
+                if (slider.getInverted())
+                  ui.scrollByBlock(BasicSliderUI.POSITIVE_SCROLL);
+                else
+                  ui.scrollByBlock(BasicSliderUI.NEGATIVE_SCROLL);
+              }
+            }
+    );
+    map.put("minScroll", 
+            new AbstractAction("minScroll") {
+              public void actionPerformed(ActionEvent event)
+              {
+                JSlider slider = (JSlider) event.getSource();
+                if (slider.getInverted())
+                  slider.setValue(slider.getMaximum());
+                else
+                  slider.setValue(slider.getMinimum());   
+              }
+            }
+    );
+    map.put("maxScroll", 
+            new AbstractAction("maxScroll") {
+              public void actionPerformed(ActionEvent event)
+              {
+                JSlider slider = (JSlider) event.getSource();
+                if (slider.getInverted())
+                  slider.setValue(slider.getMinimum());
+                else
+                  slider.setValue(slider.getMaximum());                  
+              }
+            }
+    );
+    return map;
+  }
+}

Added: llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/BasicSpinnerUI.java
URL: http://llvm.org/viewvc/llvm-project/llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/BasicSpinnerUI.java?rev=43913&view=auto

==============================================================================
--- llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/BasicSpinnerUI.java (added)
+++ llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/BasicSpinnerUI.java Thu Nov  8 16:56:19 2007
@@ -0,0 +1,561 @@
+/* BasicSpinnerUI.java --
+   Copyright (C) 2003, 2004, 2005, 2006,  Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package javax.swing.plaf.basic;
+
+import java.awt.Component;
+import java.awt.Container;
+import java.awt.Dimension;
+import java.awt.Insets;
+import java.awt.LayoutManager;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+
+import javax.swing.JButton;
+import javax.swing.JComponent;
+import javax.swing.JSpinner;
+import javax.swing.LookAndFeel;
+import javax.swing.Timer;
+import javax.swing.plaf.ComponentUI;
+import javax.swing.plaf.SpinnerUI;
+
+/**
+ * A UI delegate for the {@link JSpinner} component.
+ *
+ * @author Ka-Hing Cheung
+ *
+ * @since 1.4
+ */
+public class BasicSpinnerUI extends SpinnerUI
+{
+  /**
+   * Creates a new <code>BasicSpinnerUI</code> for the specified
+   * <code>JComponent</code>
+   *
+   * @param c  the component (ignored).
+   *
+   * @return A new instance of {@link BasicSpinnerUI}.
+   */
+  public static ComponentUI createUI(JComponent c)
+  {
+    return new BasicSpinnerUI();
+  }
+
+  /**
+   * Creates an editor component. Really, it just returns
+   * <code>JSpinner.getEditor()</code>
+   *
+   * @return a JComponent as an editor
+   *
+   * @see javax.swing.JSpinner#getEditor
+   */
+  protected JComponent createEditor()
+  {
+    return spinner.getEditor();
+  }
+
+  /**
+   * Creates a <code>LayoutManager</code> that layouts the sub components. The
+   * subcomponents are identifies by the constraint "Next", "Previous" and
+   * "Editor"
+   *
+   * @return a LayoutManager
+   *
+   * @see java.awt.LayoutManager
+   */
+  protected LayoutManager createLayout()
+  {
+    return new DefaultLayoutManager();
+  }
+
+  /**
+   * Creates the "Next" button
+   *
+   * @return the next button component
+   */
+  protected Component createNextButton()
+  {
+    JButton button = new BasicArrowButton(BasicArrowButton.NORTH);
+    return button;
+  }
+
+  /**
+   * Creates the "Previous" button
+   *
+   * @return the previous button component
+   */
+  protected Component createPreviousButton()
+  {
+    JButton button = new BasicArrowButton(BasicArrowButton.SOUTH);
+    return button;
+  }
+
+  /**
+   * Creates the <code>PropertyChangeListener</code> that will be attached by
+   * <code>installListeners</code>. It should watch for the "editor"
+   * property, when it's changed, replace the old editor with the new one,
+   * probably by calling <code>replaceEditor</code>
+   *
+   * @return a PropertyChangeListener
+   *
+   * @see #replaceEditor
+   */
+  protected PropertyChangeListener createPropertyChangeListener()
+  {
+    return new PropertyChangeListener()
+      {
+        public void propertyChange(PropertyChangeEvent event)
+        {
+          // FIXME: Add check for enabled property change. Need to
+          // disable the buttons.
+          if ("editor".equals(event.getPropertyName()))
+            BasicSpinnerUI.this.replaceEditor((JComponent) event.getOldValue(),
+                (JComponent) event.getNewValue());
+          // FIXME: Handle 'font' property change
+        }
+      };
+  }
+
+  /**
+   * Called by <code>installUI</code>. This should set various defaults
+   * obtained from <code>UIManager.getLookAndFeelDefaults</code>, as well as
+   * set the layout obtained from <code>createLayout</code>
+   *
+   * @see javax.swing.UIManager#getLookAndFeelDefaults
+   * @see #createLayout
+   * @see #installUI
+   */
+  protected void installDefaults()
+  {
+    LookAndFeel.installColorsAndFont(spinner, "Spinner.background",
+                                     "Spinner.foreground", "Spinner.font");
+    LookAndFeel.installBorder(spinner, "Spinner.border");
+    JComponent e = spinner.getEditor();
+    if (e instanceof JSpinner.DefaultEditor)
+      {
+        JSpinner.DefaultEditor de = (JSpinner.DefaultEditor) e;
+        de.getTextField().setBorder(null);  
+      }
+    spinner.setLayout(createLayout());
+    spinner.setOpaque(true);
+  }
+
+  /*
+   * Called by <code>installUI</code>, which basically adds the
+   * <code>PropertyChangeListener</code> created by
+   * <code>createPropertyChangeListener</code>
+   *
+   * @see #createPropertyChangeListener
+   * @see #installUI
+   */
+  protected void installListeners()
+  {
+    spinner.addPropertyChangeListener(listener);
+  }
+
+  /*
+   * Install listeners to the next button so that it increments the model
+   */
+  protected void installNextButtonListeners(Component c)
+  {
+    c.addMouseListener(new MouseAdapter()
+        {
+	  public void mousePressed(MouseEvent evt)
+	  {
+	    if (! spinner.isEnabled())
+	      return;
+	    increment();
+	    timer.setInitialDelay(500);
+	    timer.start();
+	  }
+
+	  public void mouseReleased(MouseEvent evt)
+	  {
+	    timer.stop();
+	  }
+
+	  void increment()
+	  {
+	    Object next = BasicSpinnerUI.this.spinner.getNextValue();
+	    if (next != null)
+	      BasicSpinnerUI.this.spinner.getModel().setValue(next);
+	  }
+
+	  volatile boolean mouseDown;
+	  Timer timer = new Timer(50,
+	                          new ActionListener()
+	      {
+		public void actionPerformed(ActionEvent event)
+		{
+		  increment();
+		}
+	      });
+        });
+  }
+
+  /*
+   * Install listeners to the previous button so that it decrements the model
+   */
+  protected void installPreviousButtonListeners(Component c)
+  {
+    c.addMouseListener(new MouseAdapter()
+        {
+	  public void mousePressed(MouseEvent evt)
+	  {
+	    if (! spinner.isEnabled())
+	      return;
+	    decrement();
+	    timer.setInitialDelay(500);
+	    timer.start();
+	  }
+
+	  public void mouseReleased(MouseEvent evt)
+	  {
+	    timer.stop();
+	  }
+
+	  void decrement()
+	  {
+	    Object prev = BasicSpinnerUI.this.spinner.getPreviousValue();
+	    if (prev != null)
+	      BasicSpinnerUI.this.spinner.getModel().setValue(prev);
+	  }
+
+	  volatile boolean mouseDown;
+	  Timer timer = new Timer(50,
+	                          new ActionListener()
+	      {
+		public void actionPerformed(ActionEvent event)
+		{
+		  decrement();
+		}
+	      });
+        });
+  }
+
+  /**
+   * Install this UI to the <code>JComponent</code>, which in reality, is a
+   * <code>JSpinner</code>. Calls <code>installDefaults</code>,
+   * <code>installListeners</code>, and also adds the buttons and editor.
+   *
+   * @param c DOCUMENT ME!
+   *
+   * @see #installDefaults
+   * @see #installListeners
+   * @see #createNextButton
+   * @see #createPreviousButton
+   * @see #createEditor
+   */
+  public void installUI(JComponent c)
+  {
+    super.installUI(c);
+
+    spinner = (JSpinner) c;
+
+    installDefaults();
+    installListeners();
+
+    Component next = createNextButton();
+    Component previous = createPreviousButton();
+
+    installNextButtonListeners(next);
+    installPreviousButtonListeners(previous);
+
+    c.add(createEditor(), "Editor");
+    c.add(next, "Next");
+    c.add(previous, "Previous");
+  }
+
+  /**
+   * Replace the old editor with the new one
+   *
+   * @param oldEditor the old editor
+   * @param newEditor the new one to replace with
+   */
+  protected void replaceEditor(JComponent oldEditor, JComponent newEditor)
+  {
+    spinner.remove(oldEditor);
+    spinner.add(newEditor);
+  }
+
+  /**
+   * The reverse of <code>installDefaults</code>. Called by
+   * <code>uninstallUI</code>
+   */
+  protected void uninstallDefaults()
+  {
+    spinner.setLayout(null);
+  }
+
+  /**
+   * The reverse of <code>installListeners</code>, called by
+   * <code>uninstallUI</code>
+   */
+  protected void uninstallListeners()
+  {
+    spinner.removePropertyChangeListener(listener);
+  }
+
+  /**
+   * Called when the current L&F is replaced with another one, should call
+   * <code>uninstallDefaults</code> and <code>uninstallListeners</code> as
+   * well as remove the next/previous buttons and the editor
+   *
+   * @param c DOCUMENT ME!
+   */
+  public void uninstallUI(JComponent c)
+  {
+    super.uninstallUI(c);
+
+    uninstallDefaults();
+    uninstallListeners();
+    c.removeAll();
+  }
+
+  /** The spinner for this UI */
+  protected JSpinner spinner;
+
+  /** DOCUMENT ME! */
+  private PropertyChangeListener listener = createPropertyChangeListener();
+
+  /**
+   * A layout manager for the {@link JSpinner} component.  The spinner has
+   * three subcomponents: an editor, a 'next' button and a 'previous' button.
+   */
+  private class DefaultLayoutManager implements LayoutManager
+  {
+    /**
+     * Layout the spinners inner parts.
+     *
+     * @param parent The parent container
+     */
+    public void layoutContainer(Container parent)
+    {
+      synchronized (parent.getTreeLock())
+        {
+          Insets i = parent.getInsets();
+          boolean l2r = parent.getComponentOrientation().isLeftToRight();
+          /*
+            --------------    --------------
+            |        | n |    | n |        |
+            |   e    | - | or | - |   e    |
+            |        | p |    | p |        |
+            --------------    --------------
+          */
+          Dimension e = prefSize(editor);
+          Dimension n = prefSize(next);
+          Dimension p = prefSize(previous);
+	  Dimension s = parent.getSize();
+
+          int x = l2r ? i.left : i.right;
+          int y = i.top;
+          int w = Math.max(p.width, n.width);
+          int h = (s.height - i.bottom) / 2;
+          int e_width = s.width - w - i.left - i.right;
+
+          if (l2r)
+            {
+              setBounds(editor, x, y, e_width, 2 * h);
+              x += e_width;
+              setBounds(next, x, y, w, h);
+              y += h;
+              setBounds(previous, x, y, w, h);
+            }
+          else
+            {
+              setBounds(next, x, y + (s.height - e.height) / 2, w, h);
+              y += h;
+              setBounds(previous, x, y + (s.height - e.height) / 2, w, h);
+              x += w;
+              y -= h;
+              setBounds(editor, x, y, e_width, e.height);
+            }
+        }
+    }
+
+    /**
+     * Calculates the minimum layout size.
+     *
+     * @param parent  the parent.
+     *
+     * @return The minimum layout size.
+     */
+    public Dimension minimumLayoutSize(Container parent)
+    {
+      Dimension d = new Dimension();
+
+      if (editor != null)
+        {
+          Dimension tmp = editor.getMinimumSize();
+          d.width += tmp.width;
+          d.height = tmp.height;
+        }
+
+      int nextWidth = 0;
+      int previousWidth = 0;
+
+      if (next != null)
+        {
+          Dimension tmp = next.getMinimumSize();
+          nextWidth = tmp.width;
+        }
+      if (previous != null)
+        {
+          Dimension tmp = previous.getMinimumSize();
+          previousWidth = tmp.width;
+        }
+
+      d.width += Math.max(nextWidth, previousWidth);
+
+      return d;
+    }
+
+    /**
+     * Returns the preferred layout size of the container.
+     *
+     * @param parent DOCUMENT ME!
+     *
+     * @return DOCUMENT ME!
+     */
+    public Dimension preferredLayoutSize(Container parent)
+    {
+      Dimension d = new Dimension();
+
+      if (editor != null)
+        {
+          Dimension tmp = editor.getPreferredSize();
+          d.width += Math.max(tmp.width, 40);
+          d.height = tmp.height;
+        }
+
+      int nextWidth = 0;
+      int previousWidth = 0;
+
+      if (next != null)
+        {
+          Dimension tmp = next.getPreferredSize();
+          nextWidth = tmp.width;
+        }
+      if (previous != null)
+        {
+          Dimension tmp = previous.getPreferredSize();
+          previousWidth = tmp.width;
+        }
+
+      d.width += Math.max(nextWidth, previousWidth);
+      Insets insets = parent.getInsets();
+      d.width = d.width + insets.left + insets.right;
+      d.height = d.height + insets.top + insets.bottom;
+      return d;
+    }
+
+    /**
+     * DOCUMENT ME!
+     *
+     * @param child DOCUMENT ME!
+     */
+    public void removeLayoutComponent(Component child)
+    {
+      if (child == editor)
+        editor = null;
+      else if (child == next)
+        next = null;
+      else if (previous == child)
+        previous = null;
+    }
+
+    /**
+     * DOCUMENT ME!
+     *
+     * @param name DOCUMENT ME!
+     * @param child DOCUMENT ME!
+     */
+    public void addLayoutComponent(String name, Component child)
+    {
+      if ("Editor".equals(name))
+        editor = child;
+      else if ("Next".equals(name))
+        next = child;
+      else if ("Previous".equals(name))
+        previous = child;
+    }
+
+    /**
+     * DOCUMENT ME!
+     *
+     * @param c DOCUMENT ME!
+     *
+     * @return DOCUMENT ME!
+     */
+    private Dimension prefSize(Component c)
+    {
+      if (c == null)
+        return new Dimension();
+      else
+        return c.getPreferredSize();
+    }
+
+    /**
+     * Sets the bounds for the specified component.
+     *
+     * @param c  the component.
+     * @param x  the x-coordinate for the top-left of the component bounds.
+     * @param y  the y-coordinate for the top-left of the component bounds.
+     * @param w  the width of the bounds.
+     * @param h  the height of the bounds.
+     */
+    private void setBounds(Component c, int x, int y, int w, int h)
+    {
+      if (c != null)
+        c.setBounds(x, y, w, h);
+    }
+
+    /** The editor component. */
+    private Component editor;
+
+    /** The next button. */
+    private Component next;
+
+    /** The previous button. */
+    private Component previous;
+  }
+}

Added: llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/BasicSplitPaneDivider.java
URL: http://llvm.org/viewvc/llvm-project/llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/BasicSplitPaneDivider.java?rev=43913&view=auto

==============================================================================
--- llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/BasicSplitPaneDivider.java (added)
+++ llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/BasicSplitPaneDivider.java Thu Nov  8 16:56:19 2007
@@ -0,0 +1,887 @@
+/* BasicSplitPaneDivider.java --
+   Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package javax.swing.plaf.basic;
+
+import java.awt.Component;
+import java.awt.Container;
+import java.awt.Dimension;
+import java.awt.Graphics;
+import java.awt.Insets;
+import java.awt.LayoutManager;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseMotionListener;
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+
+import javax.swing.JButton;
+import javax.swing.JSplitPane;
+import javax.swing.SwingConstants;
+import javax.swing.border.Border;
+
+/**
+ * The divider that separates the two parts of a JSplitPane in the Basic look
+ * and feel.
+ * 
+ * <p>
+ * Implementation status: We do not have a real implementation yet. Currently,
+ * it is mostly a stub to allow compiling other parts of the
+ * javax.swing.plaf.basic package, although some parts are already
+ * functional.
+ * </p>
+ *
+ * @author Sascha Brawer (brawer_AT_dandelis.ch)
+ */
+public class BasicSplitPaneDivider extends Container
+  implements PropertyChangeListener
+{
+  /**
+   * Determined using the <code>serialver</code> tool of Apple/Sun JDK 1.3.1
+   * on MacOS X 10.1.5.
+   */
+  static final long serialVersionUID = 1463404307042803342L;
+
+  /**
+   * The width and height of the little buttons for showing and hiding parts
+   * of a JSplitPane in a single mouse click.
+   */
+  protected static final int ONE_TOUCH_SIZE = 6;
+
+  /** The distance the one touch buttons will sit from the divider's edges. */
+  protected static final int ONE_TOUCH_OFFSET = 2;
+
+  /**
+   * An object that performs the tasks associated with an ongoing drag
+   * operation, or <code>null</code> if the user is currently not dragging
+   * the divider.
+   */
+  protected DragController dragger;
+
+  /**
+   * The delegate object that is responsible for the UI of the
+   * <code>JSplitPane</code> that contains this divider.
+   */
+  protected BasicSplitPaneUI splitPaneUI;
+
+  /** The thickness of the divider in pixels. */
+  protected int dividerSize;
+
+  /** A divider that is used for layout purposes. */
+  protected Component hiddenDivider;
+
+  /** The JSplitPane containing this divider. */
+  protected JSplitPane splitPane;
+
+  /**
+   * The listener for handling mouse events from both the divider and the
+   * containing <code>JSplitPane</code>.
+   * 
+   * <p>
+   * The reason for also handling MouseEvents from the containing
+   * <code>JSplitPane</code> is that users should be able to start a drag
+   * gesture from inside the JSplitPane, but slightly outisde the divider.
+   * </p>
+   */
+  protected MouseHandler mouseHandler = new MouseHandler();
+
+  /**
+   * The current orientation of the containing <code>JSplitPane</code>, which
+   * is either {@link javax.swing.JSplitPane#HORIZONTAL_SPLIT} or {@link
+   * javax.swing.JSplitPane#VERTICAL_SPLIT}.
+   */
+  protected int orientation;
+
+  /**
+   * The button for showing and hiding the left (or top) component of the
+   * <code>JSplitPane</code>.
+   */
+  protected JButton leftButton;
+
+  /**
+   * The button for showing and hiding the right (or bottom) component of the
+   * <code>JSplitPane</code>.
+   */
+  protected JButton rightButton;
+
+  /**
+   * The border of this divider. Typically, this will be an instance of {@link
+   * javax.swing.plaf.basic.BasicBorders.SplitPaneDividerBorder}.
+   *
+   * @see #getBorder()
+   * @see #setBorder(javax.swing.border.Border)
+   */
+  private Border border;
+
+  // This is not a pixel count.
+  // This int should be able to take 3 values.
+  // left (top), middle, right(bottom)
+  //    0          1          2
+
+  /**
+   * Keeps track of where the divider should be placed when using one touch
+   * expand buttons.
+   * This is package-private to avoid an accessor method.
+   */
+  transient int currentDividerLocation = 1;
+
+  /**
+   * Constructs a new divider.
+   *
+   * @param ui the UI delegate of the enclosing <code>JSplitPane</code>.
+   */
+  public BasicSplitPaneDivider(BasicSplitPaneUI ui)
+  {
+    setLayout(new DividerLayout());
+    setBasicSplitPaneUI(ui);
+    setDividerSize(splitPane.getDividerSize());
+  }
+
+  /**
+   * Sets the delegate object that is responsible for the UI of the {@link
+   * javax.swing.JSplitPane} containing this divider.
+   *
+   * @param newUI the UI delegate, or <code>null</code> to release the
+   *        connection to the current delegate.
+   */
+  public void setBasicSplitPaneUI(BasicSplitPaneUI newUI)
+  {
+    /* Remove the connection to the existing JSplitPane. */
+    if (splitPane != null)
+      {
+	splitPane.removePropertyChangeListener(this);
+	removeMouseListener(mouseHandler);
+	removeMouseMotionListener(mouseHandler);
+	splitPane = null;
+	hiddenDivider = null;
+      }
+
+    /* Establish the connection to the new JSplitPane. */
+    splitPaneUI = newUI;
+    if (splitPaneUI != null)
+      splitPane = newUI.getSplitPane();
+    if (splitPane != null)
+      {
+	splitPane.addPropertyChangeListener(this);
+	addMouseListener(mouseHandler);
+	addMouseMotionListener(mouseHandler);
+	hiddenDivider = splitPaneUI.getNonContinuousLayoutDivider();
+	orientation = splitPane.getOrientation();
+	oneTouchExpandableChanged();
+      }
+  }
+
+  /**
+   * Returns the delegate object that is responsible for the UI of the {@link
+   * javax.swing.JSplitPane} containing this divider.
+   *
+   * @return The UI for the JSplitPane.
+   */
+  public BasicSplitPaneUI getBasicSplitPaneUI()
+  {
+    return splitPaneUI;
+  }
+
+  /**
+   * Sets the thickness of the divider.
+   *
+   * @param newSize the new width or height in pixels.
+   */
+  public void setDividerSize(int newSize)
+  {
+    this.dividerSize = newSize;
+  }
+
+  /**
+   * Retrieves the thickness of the divider.
+   *
+   * @return The thickness of the divider.
+   */
+  public int getDividerSize()
+  {
+    return dividerSize;
+  }
+
+  /**
+   * Sets the border of this divider.
+   *
+   * @param border the new border. Typically, this will be an instance of
+   *        {@link
+   *        javax.swing.plaf.basic.BasicBorders.SplitPaneBorder}.
+   *
+   * @since 1.3
+   */
+  public void setBorder(Border border)
+  {
+    if (border != this.border)
+      {
+	Border oldValue = this.border;
+	this.border = border;
+	firePropertyChange("border", oldValue, border);
+      }
+  }
+
+  /**
+   * Retrieves the border of this divider.
+   *
+   * @return the current border, or <code>null</code> if no border has been
+   *         set.
+   *
+   * @since 1.3
+   */
+  public Border getBorder()
+  {
+    return border;
+  }
+
+  /**
+   * Retrieves the insets of the divider. If a border has been installed on
+   * the divider, the result of calling its <code>getBorderInsets</code>
+   * method is returned. Otherwise, the inherited implementation will be
+   * invoked.
+   *
+   * @see javax.swing.border.Border#getBorderInsets(java.awt.Component)
+   */
+  public Insets getInsets()
+  {
+    if (border != null)
+      return border.getBorderInsets(this);
+    else
+      return super.getInsets();
+  }
+
+  /**
+   * Returns the preferred size of this divider, which is
+   * <code>dividerSize</code> by <code>dividerSize</code> pixels.
+   *
+   * @return The preferred size of the divider.
+   */
+  public Dimension getPreferredSize()
+  {
+    return getLayout().preferredLayoutSize(this);
+  }
+
+  /**
+   * Returns the minimal size of this divider, which is
+   * <code>dividerSize</code> by <code>dividerSize</code> pixels.
+   *
+   * @return The minimal size of the divider.
+   */
+  public Dimension getMinimumSize()
+  {
+    return getPreferredSize();
+  }
+
+  /**
+   * Processes events from the <code>JSplitPane</code> that contains this
+   * divider.
+   *
+   * @param e The PropertyChangeEvent.
+   */
+  public void propertyChange(PropertyChangeEvent e)
+  {
+    if (e.getPropertyName().equals(JSplitPane.ONE_TOUCH_EXPANDABLE_PROPERTY))
+      oneTouchExpandableChanged();
+    else if (e.getPropertyName().equals(JSplitPane.ORIENTATION_PROPERTY))
+      {
+	orientation = splitPane.getOrientation();
+	if (splitPane.isOneTouchExpandable())
+	  {
+	    layout();
+	    repaint();
+	  }
+      }
+    else if (e.getPropertyName().equals(JSplitPane.DIVIDER_SIZE_PROPERTY))
+      dividerSize = splitPane.getDividerSize();
+  }
+
+  /**
+   * Paints the divider by painting its border.
+   *
+   * @param g The Graphics Object to paint with.
+   */
+  public void paint(Graphics g)
+  {
+    Dimension dividerSize;
+
+    super.paint(g);
+    if (border != null)
+      {
+	dividerSize = getSize();
+	border.paintBorder(this, g, 0, 0, dividerSize.width, dividerSize.height);
+      }
+    if (splitPane.isOneTouchExpandable())
+      {
+        ((BasicArrowButton) rightButton).paint(g);
+        ((BasicArrowButton) leftButton).paint(g);
+      }
+  }
+
+  /**
+   * Reacts to changes of the <code>oneToughExpandable</code> property of the
+   * containing <code>JSplitPane</code>.
+   */
+  protected void oneTouchExpandableChanged()
+  {
+    if (splitPane.isOneTouchExpandable())
+      {
+	leftButton = createLeftOneTouchButton();
+	rightButton = createRightOneTouchButton();
+	add(leftButton);
+	add(rightButton);
+
+	leftButton.addMouseListener(mouseHandler);
+	rightButton.addMouseListener(mouseHandler);
+
+	// Set it to 1.
+	currentDividerLocation = 1;
+      }
+    else
+      {
+	if (leftButton != null && rightButton != null)
+	  {
+	    leftButton.removeMouseListener(mouseHandler);
+	    rightButton.removeMouseListener(mouseHandler);
+
+	    remove(leftButton);
+	    remove(rightButton);
+	    leftButton = null;
+	    rightButton = null;
+	  }
+      }
+    layout();
+    repaint();
+  }
+
+  /**
+   * Creates a button for showing and hiding the left (or top) part of a
+   * <code>JSplitPane</code>.
+   *
+   * @return The left one touch button.
+   */
+  protected JButton createLeftOneTouchButton()
+  {
+    int dir = SwingConstants.WEST;
+    if (orientation == JSplitPane.VERTICAL_SPLIT)
+      dir = SwingConstants.NORTH;
+    JButton button = new BasicArrowButton(dir);
+    button.setBorder(null);
+
+    return button;
+  }
+
+  /**
+   * Creates a button for showing and hiding the right (or bottom) part of a
+   * <code>JSplitPane</code>.
+   *
+   * @return The right one touch button.
+   */
+  protected JButton createRightOneTouchButton()
+  {
+    int dir = SwingConstants.EAST;
+    if (orientation == JSplitPane.VERTICAL_SPLIT)
+      dir = SwingConstants.SOUTH;
+    JButton button = new BasicArrowButton(dir);
+    button.setBorder(null);
+    return button;
+  }
+
+  /**
+   * Prepares the divider for dragging by calling the
+   * <code>startDragging</code> method of the UI delegate of the enclosing
+   * <code>JSplitPane</code>.
+   *
+   * @see BasicSplitPaneUI#startDragging()
+   */
+  protected void prepareForDragging()
+  {
+    if (splitPaneUI != null)
+      splitPaneUI.startDragging();
+  }
+
+  /**
+   * Drags the divider to a given location by calling the
+   * <code>dragDividerTo</code> method of the UI delegate of the enclosing
+   * <code>JSplitPane</code>.
+   *
+   * @param location the new location of the divider.
+   *
+   * @see BasicSplitPaneUI#dragDividerTo(int location)
+   */
+  protected void dragDividerTo(int location)
+  {
+    if (splitPaneUI != null)
+      splitPaneUI.dragDividerTo(location);
+  }
+
+  /**
+   * Finishes a dragging gesture by calling the <code>finishDraggingTo</code>
+   * method of the UI delegate of the enclosing <code>JSplitPane</code>.
+   *
+   * @param location the new, final location of the divider.
+   *
+   * @see BasicSplitPaneUI#finishDraggingTo(int location)
+   */
+  protected void finishDraggingTo(int location)
+  {
+    if (splitPaneUI != null)
+      splitPaneUI.finishDraggingTo(location);
+  }
+
+  /**
+   * This helper method moves the divider to one of the  three locations when
+   * using one touch expand buttons. Location 0 is the left (or top) most
+   * location. Location 1 is the middle. Location 2 is the right (or bottom)
+   * most location.
+   * This is package-private to avoid an accessor method.
+   *
+   * @param locationIndex The location to move to.
+   */
+  void moveDividerTo(int locationIndex)
+  {
+    Insets insets = splitPane.getInsets();
+    switch (locationIndex)
+      {
+      case 1:
+	splitPane.setDividerLocation(splitPane.getLastDividerLocation());
+	break;
+      case 0:
+	int top = (orientation == JSplitPane.HORIZONTAL_SPLIT) ? insets.left
+	                                                       : insets.top;
+	splitPane.setDividerLocation(top);
+	break;
+      case 2:
+	int bottom;
+	if (orientation == JSplitPane.HORIZONTAL_SPLIT)
+	  bottom = splitPane.getBounds().width - insets.right - dividerSize;
+	else
+	  bottom = splitPane.getBounds().height - insets.bottom - dividerSize;
+	splitPane.setDividerLocation(bottom);
+	break;
+      }
+  }
+
+  /**
+   * The listener for handling mouse events from both the divider and the
+   * containing <code>JSplitPane</code>.
+   * 
+   * <p>
+   * The reason for also handling MouseEvents from the containing
+   * <code>JSplitPane</code> is that users should be able to start a drag
+   * gesture from inside the JSplitPane, but slightly outisde the divider.
+   * </p>
+   *
+   * @author Sascha Brawer (brawer_AT_dandelis.ch)
+   */
+  protected class MouseHandler extends MouseAdapter
+    implements MouseMotionListener
+  {
+    /** Keeps track of whether a drag is occurring. */
+    private transient boolean isDragging;
+
+    /**
+     * This method is called when the mouse is pressed.
+     *
+     * @param e The MouseEvent.
+     */
+    public void mousePressed(MouseEvent e)
+    {
+      if (splitPane.isOneTouchExpandable())
+        {
+	  if (e.getSource() == leftButton)
+	    {
+	      currentDividerLocation--;
+	      if (currentDividerLocation < 0)
+		currentDividerLocation = 0;
+	      moveDividerTo(currentDividerLocation);
+	      return;
+	    }
+	  else if (e.getSource() == rightButton)
+	    {
+	      currentDividerLocation++;
+	      if (currentDividerLocation > 2)
+		currentDividerLocation = 2;
+	      moveDividerTo(currentDividerLocation);
+	      return;
+	    }
+        }
+      isDragging = true;
+      currentDividerLocation = 1;
+      if (orientation == JSplitPane.HORIZONTAL_SPLIT)
+	dragger = new DragController(e);
+      else
+	dragger = new VerticalDragController(e);
+      prepareForDragging();
+    }
+
+    /**
+     * This method is called when the mouse is released.
+     *
+     * @param e The MouseEvent.
+     */
+    public void mouseReleased(MouseEvent e)
+    {
+      if (isDragging)
+        dragger.completeDrag(e);
+      isDragging = false;
+    }
+
+    /**
+     * Repeatedly invoked when the user is dragging the mouse cursor while
+     * having pressed a mouse button.
+     *
+     * @param e The MouseEvent.
+     */
+    public void mouseDragged(MouseEvent e)
+    {
+      if (dragger != null)
+        dragger.continueDrag(e);
+    }
+
+    /**
+     * Repeatedly invoked when the user is dragging the mouse cursor without
+     * having pressed a mouse button.
+     *
+     * @param e The MouseEvent.
+     */
+    public void mouseMoved(MouseEvent e)
+    {
+      // Do nothing.
+    }
+  }
+
+  /**
+   * Performs the tasks associated with an ongoing drag operation.
+   *
+   * @author Sascha Brawer (brawer_AT_dandelis.ch)
+   */
+  protected class DragController
+  {
+    /**
+     * The difference between where the mouse is clicked and the  initial
+     * divider location.
+     */
+    transient int offset;
+
+    /**
+     * Creates a new DragController object.
+     *
+     * @param e The MouseEvent to initialize with.
+     */
+    protected DragController(MouseEvent e)
+    {
+      offset = e.getX();
+    }
+
+    /**
+     * This method returns true if the divider can move.
+     *
+     * @return True if dragging is allowed.
+     */
+    protected boolean isValid()
+    {
+      // Views can always be resized?
+      return true;
+    }
+
+    /**
+     * Returns a position for the divider given the MouseEvent.
+     *
+     * @param e MouseEvent.
+     *
+     * @return The position for the divider to move to.
+     */
+    protected int positionForMouseEvent(MouseEvent e)
+    {
+      return e.getX() + getX() - offset;
+    }
+
+    /**
+     * This method returns one of the two paramters for the orientation. In
+     * this case, it returns x.
+     *
+     * @param x The x coordinate.
+     * @param y The y coordinate.
+     *
+     * @return The x coordinate.
+     */
+    protected int getNeededLocation(int x, int y)
+    {
+      return x;
+    }
+
+    /**
+     * This method is called to pass on the drag information to the UI through
+     * dragDividerTo.
+     *
+     * @param newX The x coordinate of the MouseEvent.
+     * @param newY The y coordinate of the MouseEvent.
+     */
+    protected void continueDrag(int newX, int newY)
+    {
+      if (isValid())
+	dragDividerTo(adjust(newX, newY));
+    }
+
+    /**
+     * This method is called to pass on the drag information  to the UI
+     * through dragDividerTo.
+     *
+     * @param e The MouseEvent.
+     */
+    protected void continueDrag(MouseEvent e)
+    {
+      if (isValid())
+	dragDividerTo(positionForMouseEvent(e));
+    }
+
+    /**
+     * This method is called to finish the drag session  by calling
+     * finishDraggingTo.
+     *
+     * @param x The x coordinate of the MouseEvent.
+     * @param y The y coordinate of the MouseEvent.
+     */
+    protected void completeDrag(int x, int y)
+    {
+      finishDraggingTo(adjust(x, y));
+    }
+
+    /**
+     * This method is called to finish the drag session  by calling
+     * finishDraggingTo.
+     *
+     * @param e The MouseEvent.
+     */
+    protected void completeDrag(MouseEvent e)
+    {
+      finishDraggingTo(positionForMouseEvent(e));
+    }
+
+    /**
+     * This is a helper method that includes the offset in the needed
+     * location.
+     *
+     * @param x The x coordinate of the MouseEvent.
+     * @param y The y coordinate of the MouseEvent.
+     *
+     * @return The needed location adjusted by the offsets.
+     */
+    int adjust(int x, int y)
+    {
+      return getNeededLocation(x, y) + getX() - offset;
+    }
+  }
+
+  /**
+   * This is a helper class that controls dragging when  the orientation is
+   * VERTICAL_SPLIT.
+   */
+  protected class VerticalDragController extends DragController
+  {
+    /**
+     * Creates a new VerticalDragController object.
+     *
+     * @param e The MouseEvent to initialize with.
+     */
+    protected VerticalDragController(MouseEvent e)
+    {
+      super(e);
+      offset = e.getY();
+    }
+
+    /**
+     * This method returns one of the two parameters given the orientation. In
+     * this case, it returns y.
+     *
+     * @param x The x coordinate of the MouseEvent.
+     * @param y The y coordinate of the MouseEvent.
+     *
+     * @return The y coordinate.
+     */
+    protected int getNeededLocation(int x, int y)
+    {
+      return y;
+    }
+
+    /**
+     * This method returns the new location of the divider given a MouseEvent.
+     *
+     * @param e The MouseEvent.
+     *
+     * @return The new location of the divider.
+     */
+    protected int positionForMouseEvent(MouseEvent e)
+    {
+      return e.getY() + getY() - offset;
+    }
+
+    /**
+     * This is a helper method that includes the offset in the needed
+     * location.
+     *
+     * @param x The x coordinate of the MouseEvent.
+     * @param y The y coordinate of the MouseEvent.
+     *
+     * @return The needed location adjusted by the offsets.
+     */
+    int adjust(int x, int y)
+    {
+      return getNeededLocation(x, y) + getY() - offset;
+    }
+  }
+
+  /**
+   * This helper class acts as the Layout Manager for the divider.
+   */
+  protected class DividerLayout implements LayoutManager
+  {
+    /**
+     * Creates a new DividerLayout object.
+     */
+    protected DividerLayout()
+    {
+      // Nothing to do here.
+    }
+
+    /**
+     * This method is called when a Component is added.
+     *
+     * @param string The constraints string.
+     * @param c The Component to add.
+     */
+    public void addLayoutComponent(String string, Component c)
+    {
+      // Do nothing.
+    }
+
+    /**
+     * This method is called to lay out the container.
+     *
+     * @param c The container to lay out.
+     */
+    public void layoutContainer(Container c)
+    {
+      if (splitPane.isOneTouchExpandable())
+        {
+	  changeButtonOrientation();
+	  positionButtons();
+        }
+    }
+
+    /**
+     * This method returns the minimum layout size.
+     *
+     * @param c The container to calculate for.
+     *
+     * @return The minimum layout size.
+     */
+    public Dimension minimumLayoutSize(Container c)
+    {
+      return preferredLayoutSize(c);
+    }
+
+    /**
+     * This method returns the preferred layout size.
+     *
+     * @param c The container to calculate for.
+     *
+     * @return The preferred layout size.
+     */
+    public Dimension preferredLayoutSize(Container c)
+    {
+      return new Dimension(dividerSize, dividerSize);
+    }
+
+    /**
+     * This method is called when a component is removed.
+     *
+     * @param c The component to remove.
+     */
+    public void removeLayoutComponent(Component c)
+    {
+      // Do nothing.
+    }
+
+    /**
+     * This method changes the button orientation when the orientation of the
+     * SplitPane changes.
+     */
+    private void changeButtonOrientation()
+    {
+      if (orientation == JSplitPane.HORIZONTAL_SPLIT)
+        {
+	  ((BasicArrowButton) rightButton).setDirection(SwingConstants.EAST);
+	  ((BasicArrowButton) leftButton).setDirection(SwingConstants.WEST);
+        }
+      else
+        {
+	  ((BasicArrowButton) rightButton).setDirection(SwingConstants.SOUTH);
+	  ((BasicArrowButton) leftButton).setDirection(SwingConstants.NORTH);
+        }
+    }
+
+    /**
+     * This method sizes and positions the buttons.
+     */
+    private void positionButtons()
+    {
+      int w = 0;
+      int h = 0;
+      if (orientation == JSplitPane.HORIZONTAL_SPLIT)
+        {
+	  rightButton.setLocation(ONE_TOUCH_OFFSET, ONE_TOUCH_OFFSET);
+	  leftButton.setLocation(ONE_TOUCH_OFFSET,
+	                         ONE_TOUCH_OFFSET + 2 * ONE_TOUCH_SIZE);
+	  w = dividerSize - 2 * ONE_TOUCH_OFFSET;
+	  h = 2 * ONE_TOUCH_SIZE;
+        }
+      else
+        {
+	  leftButton.setLocation(ONE_TOUCH_OFFSET, ONE_TOUCH_OFFSET);
+	  rightButton.setLocation(ONE_TOUCH_OFFSET + 2 * ONE_TOUCH_SIZE,
+	                          ONE_TOUCH_OFFSET);
+	  h = dividerSize - 2 * ONE_TOUCH_OFFSET;
+	  w = 2 * ONE_TOUCH_SIZE;
+        }
+      Dimension dims = new Dimension(w, h);
+      leftButton.setSize(dims);
+      rightButton.setSize(dims);
+    }
+  }
+}

Added: llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/BasicSplitPaneUI.java
URL: http://llvm.org/viewvc/llvm-project/llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/BasicSplitPaneUI.java?rev=43913&view=auto

==============================================================================
--- llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/BasicSplitPaneUI.java (added)
+++ llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/BasicSplitPaneUI.java Thu Nov  8 16:56:19 2007
@@ -0,0 +1,1683 @@
+/* BasicSplitPaneUI.java --
+   Copyright (C) 2003, 2004, 2005, 2006, Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package javax.swing.plaf.basic;
+
+import java.awt.Canvas;
+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.LayoutManager2;
+import java.awt.Point;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.FocusAdapter;
+import java.awt.event.FocusEvent;
+import java.awt.event.FocusListener;
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+
+import javax.swing.AbstractAction;
+import javax.swing.ActionMap;
+import javax.swing.InputMap;
+import javax.swing.JComponent;
+import javax.swing.JSlider;
+import javax.swing.JSplitPane;
+import javax.swing.KeyStroke;
+import javax.swing.LookAndFeel;
+import javax.swing.SwingUtilities;
+import javax.swing.UIManager;
+import javax.swing.plaf.ActionMapUIResource;
+import javax.swing.plaf.ComponentUI;
+import javax.swing.plaf.SplitPaneUI;
+import javax.swing.plaf.UIResource;
+
+/**
+ * This is the Basic Look and Feel implementation of the SplitPaneUI  class.
+ */
+public class BasicSplitPaneUI extends SplitPaneUI
+{
+  /**
+   * This Layout Manager controls the position and size of the components when
+   * the JSplitPane's orientation is HORIZONTAL_SPLIT.
+   *
+   * @specnote Apparently this class was intended to be protected,
+   *           but was made public by a compiler bug and is now
+   *           public for compatibility.
+   */
+  public class BasicHorizontalLayoutManager implements LayoutManager2
+  {
+    // 3 components at a time.
+    // LEFT/TOP = 0
+    // RIGHT/BOTTOM = 1
+    // DIVIDER = 2    
+
+    /**
+     * This array contains the components in the JSplitPane. The  left/top
+     * component is at index 0, the right/bottom is at 1, and the divider is
+     * at 2.
+     */
+    protected Component[] components = new Component[3];
+
+    // These are the _current_ widths of the associated component.
+
+    /**
+     * This array contains the current width (for HORIZONTAL_SPLIT) or height
+     * (for VERTICAL_SPLIT) of the components. The indices are the same as
+     * for components.
+     */
+    protected int[] sizes = new int[3];
+
+    /**
+     * Creates a new instance. This is package private because the reference
+     * implementation has no public constructor either. Still, we need to
+     * call it from BasicVerticalLayoutManager.
+     */
+    BasicHorizontalLayoutManager()
+    {
+      // Nothing to do here.
+    }
+
+    /**
+     * This method adds the component given to the JSplitPane. The position of
+     * the component is given by the constraints object.
+     *
+     * @param comp The Component to add.
+     * @param constraints The constraints that bind the object.
+     */
+    public void addLayoutComponent(Component comp, Object constraints)
+    {
+      addLayoutComponent((String) constraints, comp);
+    }
+
+    /**
+     * This method is called to add a Component to the JSplitPane. The
+     * placement string determines where the Component will be placed. The
+     * string should be one of LEFT, RIGHT, TOP, BOTTOM or null (signals that
+     * the component is the divider).
+     *
+     * @param place The placement of the Component.
+     * @param component The Component to add.
+     *
+     * @throws IllegalArgumentException DOCUMENT ME!
+     */
+    public void addLayoutComponent(String place, Component component)
+    {
+      int i = 0;
+      if (place == null)
+        i = 2;
+      else if (place.equals(JSplitPane.TOP) || place.equals(JSplitPane.LEFT))
+        i = 0;
+      else if (place.equals(JSplitPane.BOTTOM)
+               || place.equals(JSplitPane.RIGHT))
+        i = 1;
+      else
+        throw new IllegalArgumentException("Illegal placement in JSplitPane");
+      components[i] = component;
+      resetSizeAt(i);
+      splitPane.revalidate();
+      splitPane.repaint();
+    }
+
+    /**
+     * This method returns the width of the JSplitPane minus the insets.
+     *
+     * @param containerSize The Dimensions of the JSplitPane.
+     * @param insets The Insets of the JSplitPane.
+     *
+     * @return The width of the JSplitPane minus the insets.
+     */
+    protected int getAvailableSize(Dimension containerSize, Insets insets)
+    {
+      return containerSize.width - insets.left - insets.right;
+    }
+
+    /**
+     * This method returns the given insets left value. If the  given inset is
+     * null, then 0 is returned.
+     *
+     * @param insets The Insets to use with the JSplitPane.
+     *
+     * @return The inset's left value.
+     */
+    protected int getInitialLocation(Insets insets)
+    {
+      if (insets != null)
+        return insets.left;
+      return 0;
+    }
+
+    /**
+     * This specifies how a component is aligned with respect to  other
+     * components in the x fdirection.
+     *
+     * @param target The container.
+     *
+     * @return The component's alignment.
+     */
+    public float getLayoutAlignmentX(Container target)
+    {
+      return target.getAlignmentX();
+    }
+
+    /**
+     * This specifies how a component is aligned with respect to  other
+     * components in the y direction.
+     *
+     * @param target The container.
+     *
+     * @return The component's alignment.
+     */
+    public float getLayoutAlignmentY(Container target)
+    {
+      return target.getAlignmentY();
+    }
+
+    /**
+     * This method returns the preferred width of the component.
+     *
+     * @param c The component to measure.
+     *
+     * @return The preferred width of the component.
+     */
+    protected int getPreferredSizeOfComponent(Component c)
+    {
+      Dimension dims = c.getPreferredSize();
+      if (dims != null)
+        return dims.width;
+      return 0;
+    }
+
+    /**
+     * This method returns the current width of the component.
+     *
+     * @param c The component to measure.
+     *
+     * @return The width of the component.
+     */
+    protected int getSizeOfComponent(Component c)
+    {
+      return c.getWidth();
+    }
+
+    /**
+     * This method returns the sizes array.
+     *
+     * @return The sizes array.
+     */
+    protected int[] getSizes()
+    {
+      return sizes;
+    }
+
+    /**
+     * This method invalidates the layout. It does nothing.
+     *
+     * @param c The container to invalidate.
+     */
+    public void invalidateLayout(Container c)
+    {
+      // DO NOTHING
+    }
+
+    /**
+     * This method lays out the components in the container.
+     *
+     * @param container The container to lay out.
+     */
+    public void layoutContainer(Container container)
+    {
+      if (container instanceof JSplitPane)
+        {
+          JSplitPane split = (JSplitPane) container;
+          distributeExtraSpace();
+          Insets insets = split.getInsets();
+          Dimension dims = split.getSize();
+          int loc = getInitialLocation(insets);
+          int available = getAvailableSize(dims, insets);
+          sizes[0] = getDividerLocation(split) - loc;
+          sizes[1] = available - sizes[0] - sizes[2];
+          // The size of the divider won't change.
+
+          // Layout component#1.
+          setComponentToSize(components[0], sizes[0], loc, insets, dims);
+          // Layout divider.
+          loc += sizes[0];
+          setComponentToSize(components[2], sizes[2], loc, insets, dims);
+          // Layout component#2. 
+          loc += sizes[2];
+          setComponentToSize(components[1], sizes[1], loc, insets, dims);
+        }
+    }
+
+    /**
+     * This method returns the maximum size for the container given the
+     * components. It returns a new Dimension object that has width and
+     * height equal to Integer.MAX_VALUE.
+     *
+     * @param target The container to measure.
+     *
+     * @return The maximum size.
+     */
+    public Dimension maximumLayoutSize(Container target)
+    {
+      return new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE);
+    }
+
+    /**
+     * This method returns the container's minimum size. The  minimum width is
+     * the sum of all the component's minimum widths. The minimum height is
+     * the maximum of  all the components' minimum heights.
+     *
+     * @param target The container to measure.
+     *
+     * @return The minimum size.
+     */
+    public Dimension minimumLayoutSize(Container target)
+    {
+      if (target instanceof JSplitPane)
+        {
+          JSplitPane split = (JSplitPane) target;
+          Insets insets = target.getInsets();
+
+          int height = 0;
+          int width = 0;
+          for (int i = 0; i < components.length; i++)
+            {
+              if (components[i] == null)
+                continue;
+              Dimension dims = components[i].getMinimumSize();
+              if (dims != null)
+                {
+                  width += dims.width;
+                  height = Math.max(height, dims.height);
+                }
+            }
+          return new Dimension(width, height);
+        }
+      return null;
+    }
+
+    /**
+     * This method returns the container's preferred size. The preferred width
+     * is the sum of all the component's preferred widths. The preferred
+     * height is the maximum of all the components' preferred heights.
+     *
+     * @param target The container to measure.
+     *
+     * @return The preferred size.
+     */
+    public Dimension preferredLayoutSize(Container target)
+    {
+      if (target instanceof JSplitPane)
+        {
+          JSplitPane split = (JSplitPane) target;
+          Insets insets = target.getInsets();
+
+          int height = 0;
+          int width = 0;
+          for (int i = 0; i < components.length; i++)
+            {
+              if (components[i] == null)
+                continue;
+              Dimension dims = components[i].getPreferredSize();
+              if (dims != null)
+                {
+                  width += dims.width;
+                  if (!(components[i] instanceof BasicSplitPaneDivider))
+                    height = Math.max(height, dims.height);
+                }
+            }
+          return new Dimension(width, height);
+        }
+      return null;
+    }
+
+    /**
+     * This method removes the component from the layout.
+     *
+     * @param component The component to remove from the layout.
+     */
+    public void removeLayoutComponent(Component component)
+    {
+      for (int i = 0; i < components.length; i++)
+        {
+          if (component == components[i])
+            {
+              components[i] = null;
+              sizes[i] = 0;
+            }
+        }
+    }
+
+    /**
+     * This method resets the size of Component to the preferred size.
+     *
+     * @param index The index of the component to reset.
+     */
+    protected void resetSizeAt(int index)
+    {
+      if (components[index] != null)
+        sizes[index] = getPreferredSizeOfComponent(components[index]);
+    }
+
+    /**
+     * This method resets the sizes of all the components.
+     */
+    public void resetToPreferredSizes()
+    {
+      for (int i = 0; i < components.length; i++)
+        resetSizeAt(i);
+      setDividerLocation(splitPane,
+                         getInitialLocation(splitPane.getInsets()) + sizes[0]);
+    }
+
+    /**
+     * This methods sets the bounds of the given component. The width is the
+     * size. The height is the container size minus the  top and bottom
+     * inset. The x coordinate is the location given.  The y coordinate is
+     * the top inset.
+     *
+     * @param c The component to set.
+     * @param size The width of the component.
+     * @param location The x coordinate.
+     * @param insets The insets to use.
+     * @param containerSize The height of the container.
+     */
+    protected void setComponentToSize(Component c, int size, int location,
+                                      Insets insets, Dimension containerSize)
+    { 
+      int w = size;
+      int h = containerSize.height - insets.top - insets.bottom;
+      int x = location;
+      int y = insets.top;
+      c.setBounds(x, y, w, h);
+    }
+
+    /**
+     * This method stores the given int array as the new sizes array.
+     *
+     * @param newSizes The array to use as sizes.
+     */
+    protected void setSizes(int[] newSizes)
+    {
+      sizes = newSizes;
+    }
+
+    /**
+     * This method determines the size of each  component. It should be called
+     * when a new Layout Manager is created for an existing JSplitPane.
+     */
+    protected void updateComponents()
+    {
+      Component left = splitPane.getLeftComponent();
+      Component right = splitPane.getRightComponent();
+
+      if (left != null)
+        {
+          components[0] = left;
+          resetSizeAt(0);
+        }
+      if (right != null)
+        {
+          components[1] = right;
+          resetSizeAt(1);
+        }
+      components[2] = divider;
+      resetSizeAt(2);
+    }
+
+    /**
+     * This method resizes the left and right components to fit inside the
+     * JSplitPane when there is extra space.
+     */
+    void distributeExtraSpace()
+    {
+      // FIXME: This needs to be reimplemented correctly.
+    }
+
+    /**
+     * This method returns the minimum width of the  component at the given
+     * index.
+     *
+     * @param index The index to check.
+     *
+     * @return The minimum width.
+     */
+    int minimumSizeOfComponent(int index)
+    {
+      Dimension dims = components[index].getMinimumSize();
+      if (dims != null)
+        return dims.width;
+      else
+        return 0;
+    }
+  } //end BasicHorizontalLayoutManager
+
+  /**
+   * This class is the Layout Manager for the JSplitPane when the orientation
+   * is VERTICAL_SPLIT.
+   *
+   * @specnote Apparently this class was intended to be protected,
+   *           but was made public by a compiler bug and is now
+   *           public for compatibility.
+   */
+  public class BasicVerticalLayoutManager
+    extends BasicHorizontalLayoutManager
+  {
+    /**
+     * This method returns the height of the container minus the top and
+     * bottom inset.
+     *
+     * @param containerSize The size of the container.
+     * @param insets The insets of the container.
+     *
+     * @return The height minus top and bottom inset.
+     */
+    protected int getAvailableSize(Dimension containerSize, Insets insets)
+    {
+      return containerSize.height - insets.top - insets.bottom;
+    }
+
+    /**
+     * This method returns the top inset.
+     *
+     * @param insets The Insets to use.
+     *
+     * @return The top inset.
+     */
+    protected int getInitialLocation(Insets insets)
+    {
+      return insets.top;
+    }
+
+    /**
+     * This method returns the preferred height of the component.
+     *
+     * @param c The component to measure.
+     *
+     * @return The preferred height of the component.
+     */
+    protected int getPreferredSizeOfComponent(Component c)
+    {
+      Dimension dims = c.getPreferredSize();
+      if (dims != null)
+        return dims.height;
+      return 0;
+    }
+
+    /**
+     * This method returns the current height of the component.
+     *
+     * @param c The component to measure.
+     *
+     * @return The current height of the component.
+     */
+    protected int getSizeOfComponent(Component c)
+    {
+      return c.getHeight();
+    }
+
+    /**
+     * This method returns the minimum layout size. The minimum height is the
+     * sum of all the components' minimum heights. The minimum width is the
+     * maximum of all the  components' minimum widths.
+     *
+     * @param container The container to measure.
+     *
+     * @return The minimum size.
+     */
+    public Dimension minimumLayoutSize(Container container)
+    {
+      if (container instanceof JSplitPane)
+        {
+          JSplitPane split = (JSplitPane) container;
+          Insets insets = container.getInsets();
+
+          int height = 0;
+          int width = 0;
+          for (int i = 0; i < components.length; i++)
+            {
+              if (components[i] == null)
+                continue;
+              Dimension dims = components[i].getMinimumSize();
+              if (dims != null)
+                {
+                  height += dims.height;
+                  width = Math.max(width, dims.width);
+                }
+            }
+          return new Dimension(width, height);
+        }
+      return null;
+    }
+
+    /**
+     * This method returns the preferred layout size. The preferred height is
+     * the sum of all the components'  preferred heights. The preferred width
+     * is the maximum of  all the components' preferred widths.
+     *
+     * @param container The container to measure.
+     *
+     * @return The preferred size.
+     */
+    public Dimension preferredLayoutSize(Container container)
+    {
+      if (container instanceof JSplitPane)
+        {
+          JSplitPane split = (JSplitPane) container;
+          Insets insets = container.getInsets();
+
+          int height = 0;
+          int width = 0;
+          for (int i = 0; i < components.length; i++)
+            {
+              if (components[i] == null)
+                continue;
+              Dimension dims = components[i].getPreferredSize();
+              if (dims != null)
+                {
+                  height += dims.height;
+                  width = Math.max(width, dims.width);
+                }
+            }
+          return new Dimension(width, height);
+        }
+      return null;
+    }
+
+    /**
+     * This method sets the bounds of the given component. The y coordinate is
+     * the location given. The x coordinate is the left inset. The height is
+     * the size given. The width is the container size minus the left and
+     * right inset.
+     *
+     * @param c The component to set bounds for.
+     * @param size The height.
+     * @param location The y coordinate.
+     * @param insets The insets to use.
+     * @param containerSize The container's size.
+     */
+    protected void setComponentToSize(Component c, int size, int location,
+                                      Insets insets, Dimension containerSize)
+    {
+      int y = location;
+      int x = insets.left;
+      int h = size;
+      int w = containerSize.width - insets.left - insets.right;
+      c.setBounds(x, y, w, h);
+    }
+
+    /**
+     * This method returns the minimum height of the component at the given
+     * index.
+     *
+     * @param index The index of the component to check.
+     *
+     * @return The minimum height of the given component.
+     */
+    int minimumSizeOfComponent(int index)
+    {
+      Dimension dims = components[index].getMinimumSize();
+      if (dims != null)
+        return dims.height;
+      else
+        return 0;
+    }
+  }
+
+  /**
+   * This class handles FocusEvents from the JComponent.
+   *
+   * @specnote Apparently this class was intended to be protected,
+   *           but was made public by a compiler bug and is now
+   *           public for compatibility.
+   */
+  public class FocusHandler extends FocusAdapter
+  {
+    /**
+     * This method is called when the JSplitPane gains focus.
+     *
+     * @param ev The FocusEvent.
+     */
+    public void focusGained(FocusEvent ev)
+    {
+      // repaint the divider because its background color may change due to
+      // the focus state...
+      divider.repaint();
+    }
+
+    /**
+     * This method is called when the JSplitPane loses focus.
+     *
+     * @param ev The FocusEvent.
+     */
+    public void focusLost(FocusEvent ev)
+    {
+      // repaint the divider because its background color may change due to
+      // the focus state...
+      divider.repaint();
+    }
+  }
+
+  /**
+   * This is a deprecated class. It is supposed to be used for handling down
+   * and right key presses.
+   *
+   * @specnote Apparently this class was intended to be protected,
+   *           but was made public by a compiler bug and is now
+   *           public for compatibility.
+   */
+  public class KeyboardDownRightHandler implements ActionListener
+  {
+    /**
+     * This method is called when the down or right keys are pressed.
+     *
+     * @param ev The ActionEvent
+     */
+    public void actionPerformed(ActionEvent ev)
+    {
+      // FIXME: implement.
+    }
+  }
+
+  /**
+   * This is a deprecated class. It is supposed to be used for handling end
+   * key presses.
+   *
+   * @specnote Apparently this class was intended to be protected,
+   *           but was made public by a compiler bug and is now
+   *           public for compatibility.
+   */
+  public class KeyboardEndHandler implements ActionListener
+  {
+    /**
+     * This method is called when the end key is pressed.
+     *
+     * @param ev The ActionEvent.
+     */
+    public void actionPerformed(ActionEvent ev)
+    {
+      // FIXME: implement.
+    }
+  }
+
+  /**
+   * This is a deprecated class. It is supposed to be used for handling home
+   * key presses.
+   *
+   * @specnote Apparently this class was intended to be protected,
+   *           but was made public by a compiler bug and is now
+   *           public for compatibility.
+   */
+  public class KeyboardHomeHandler implements ActionListener
+  {
+    /**
+     * This method is called when the home key is pressed.
+     *
+     * @param ev The ActionEvent.
+     */
+    public void actionPerformed(ActionEvent ev)
+    {
+      // FIXME: implement.
+    }
+  }
+
+  /**
+   * This is a deprecated class. It is supposed to be used for handling resize
+   * toggles.
+   *
+   * @specnote Apparently this class was intended to be protected,
+   *           but was made public by a compiler bug and is now
+   *           public for compatibility.
+   */
+  public class KeyboardResizeToggleHandler implements ActionListener
+  {
+    /**
+     * This method is called when a resize is toggled.
+     *
+     * @param ev The ActionEvent.
+     */
+    public void actionPerformed(ActionEvent ev)
+    {
+      // FIXME: implement.
+    }
+  }
+
+  /**
+   * This is a deprecated class. It is supposed to be used for handler up and
+   * left key presses.
+   *
+   * @specnote Apparently this class was intended to be protected,
+   *           but was made public by a compiler bug and is now
+   *           public for compatibility.
+   */
+  public class KeyboardUpLeftHandler implements ActionListener
+  {
+    /**
+     * This method is called when the left or up keys are pressed.
+     *
+     * @param ev The ActionEvent.
+     */
+    public void actionPerformed(ActionEvent ev)
+    {
+      // FIXME: implement.
+    }
+  }
+
+  /**
+   * This helper class handles PropertyChangeEvents from the JSplitPane. When
+   * a property changes, this will update the UI accordingly.
+   *
+   * @specnote Apparently this class was intended to be protected,
+   *           but was made public by a compiler bug and is now
+   *           public for compatibility.
+   */
+  public class PropertyHandler implements PropertyChangeListener
+  {
+    /**
+     * This method is called whenever one of the JSplitPane's properties
+     * change.
+     *
+     * @param e DOCUMENT ME!
+     */
+    public void propertyChange(PropertyChangeEvent e)
+    {
+      if (e.getPropertyName().equals(JSplitPane.DIVIDER_SIZE_PROPERTY))
+        {
+          int newSize = splitPane.getDividerSize();
+          int[] tmpSizes = layoutManager.getSizes();
+          dividerSize = tmpSizes[2];
+          int newSpace = newSize - tmpSizes[2];
+          tmpSizes[2] = newSize;
+
+          tmpSizes[0] += newSpace / 2;
+          tmpSizes[1] += newSpace / 2;
+      
+          layoutManager.setSizes(tmpSizes);
+        }
+      else if (e.getPropertyName().equals(JSplitPane.ORIENTATION_PROPERTY))
+        {
+          int max = layoutManager.getAvailableSize(splitPane.getSize(),
+                                                   splitPane.getInsets());
+          int dividerLoc = getDividerLocation(splitPane);
+          double prop = ((double) dividerLoc) / max;
+
+          resetLayoutManager();
+          if (prop <= 1 && prop >= 0)
+            splitPane.setDividerLocation(prop);
+        }
+      // Don't have to deal with continuous_layout - only
+      // necessary in dragging modes (and it's checked
+      // every time you drag there)
+      // Don't have to deal with resize_weight (as there
+      // will be no extra space associated with this
+      // event - the changes to the weighting will
+      // be taken into account the next time the
+      // sizes change.)
+      // Don't have to deal with divider_location
+      // The method in JSplitPane calls our setDividerLocation
+      // so we'll know about those anyway.
+      // Don't have to deal with last_divider_location
+      // Although I'm not sure why, it doesn't seem to
+      // have any effect on Sun's JSplitPane.
+      // one_touch_expandable changes are dealt with
+      // by our divider.
+    }
+  }
+
+  /** The location of the divider when dragging began. */
+  protected int beginDragDividerLocation;
+
+  /** The size of the divider while dragging. */
+  protected int dividerSize;
+
+  /** The location where the last drag location ended. */
+  transient int lastDragLocation = -1;
+
+  /** The distance the divider is moved when moved by keyboard actions. */
+  // Sun defines this as 3
+  protected static int KEYBOARD_DIVIDER_MOVE_OFFSET = 3;
+
+  /** The divider that divides this JSplitPane. */
+  protected BasicSplitPaneDivider divider;
+
+  /** The listener that listens for PropertyChangeEvents from the JSplitPane. */
+  protected PropertyChangeListener propertyChangeListener;
+
+  /** The JSplitPane's focus handler. */
+  protected FocusListener focusListener;
+
+  /** @deprecated The handler for down and right key presses. */
+  protected ActionListener keyboardDownRightListener;
+
+  /** @deprecated The handler for end key presses. */
+  protected ActionListener keyboardEndListener;
+
+  /** @deprecated The handler for home key presses. */
+  protected ActionListener keyboardHomeListener;
+
+  /** @deprecated The handler for toggling resizes. */
+  protected ActionListener keyboardResizeToggleListener;
+
+  /** @deprecated The handler for up and left key presses. */
+  protected ActionListener keyboardUpLeftListener;
+
+  /** The JSplitPane's current layout manager. */
+  protected BasicHorizontalLayoutManager layoutManager;
+
+  /** @deprecated The divider resize toggle key. */
+  protected KeyStroke dividerResizeToggleKey;
+
+  /** @deprecated The down key. */
+  protected KeyStroke downKey;
+
+  /** @deprecated The end key. */
+  protected KeyStroke endKey;
+
+  /** @deprecated The home key. */
+  protected KeyStroke homeKey;
+
+  /** @deprecated The left key. */
+  protected KeyStroke leftKey;
+
+  /** @deprecated The right key. */
+  protected KeyStroke rightKey;
+
+  /** @deprecated The up key. */
+  protected KeyStroke upKey;
+
+  /** Set to true when dragging heavy weight components. */
+  protected boolean draggingHW;
+
+  /**
+   * The constraints object used when adding the non-continuous divider to the
+   * JSplitPane.
+   */
+  protected static final String NON_CONTINUOUS_DIVIDER
+    = "nonContinuousDivider";
+
+  /** The dark divider used when dragging in non-continuous layout mode. */
+  protected Component nonContinuousLayoutDivider;
+
+  /** The JSplitPane that this UI draws. */
+  protected JSplitPane splitPane;
+
+  private int dividerLocation;
+
+  /**
+   * Creates a new BasicSplitPaneUI object.
+   */
+  public BasicSplitPaneUI()
+  {
+    // Nothing to do here.
+  }
+
+  /**
+   * This method creates a new BasicSplitPaneUI for the given JComponent.
+   *
+   * @param x The JComponent to create a UI for.
+   *
+   * @return A new BasicSplitPaneUI.
+   */
+  public static ComponentUI createUI(JComponent x)
+  {
+    return new BasicSplitPaneUI();
+  }
+
+  /**
+   * This method installs the BasicSplitPaneUI for the given JComponent.
+   *
+   * @param c The JComponent to install the UI for.
+   */
+  public void installUI(JComponent c)
+  {
+    if (c instanceof JSplitPane)
+      {
+        splitPane = (JSplitPane) c;
+        installDefaults();
+        installListeners();
+        installKeyboardActions();
+      }
+  }
+
+  /**
+   * This method uninstalls the BasicSplitPaneUI for the given JComponent.
+   *
+   * @param c The JComponent to uninstall the UI for.
+   */
+  public void uninstallUI(JComponent c)
+  {
+    uninstallKeyboardActions();
+    uninstallListeners();
+    uninstallDefaults();
+
+    splitPane = null;
+  }
+
+  /**
+   * This method installs the defaults given by the Look and Feel.
+   */
+  protected void installDefaults()
+  {
+    LookAndFeel.installColors(splitPane, "SplitPane.background",
+                              "SplitPane.foreground");
+    LookAndFeel.installBorder(splitPane, "SplitPane.border");
+    divider = createDefaultDivider();
+    divider.setBorder(UIManager.getBorder("SplitPaneDivider.border"));
+    resetLayoutManager();
+    nonContinuousLayoutDivider = createDefaultNonContinuousLayoutDivider();
+    splitPane.add(divider, JSplitPane.DIVIDER);
+
+    // There is no need to add the nonContinuousLayoutDivider
+    splitPane.setDividerSize(UIManager.getInt("SplitPane.dividerSize"));
+    splitPane.setOpaque(true);
+  }
+
+  /**
+   * This method uninstalls the defaults and nulls any objects created during
+   * install.
+   */
+  protected void uninstallDefaults()
+  {
+    layoutManager = null;
+    splitPane.remove(divider);
+    divider = null;
+    nonContinuousLayoutDivider = null;
+
+    if (splitPane.getBackground() instanceof UIResource)
+      splitPane.setBackground(null);
+    if (splitPane.getBorder() instanceof UIResource)
+      splitPane.setBorder(null);
+  }
+
+  /**
+   * This method installs the listeners needed for this UI to function.
+   */
+  protected void installListeners()
+  {
+    propertyChangeListener = createPropertyChangeListener();
+    focusListener = createFocusListener();
+
+    splitPane.addPropertyChangeListener(propertyChangeListener);
+    splitPane.addFocusListener(focusListener);
+  }
+
+  /**
+   * This method uninstalls all listeners registered for the UI.
+   */
+  protected void uninstallListeners()
+  {
+    splitPane.removePropertyChangeListener(propertyChangeListener);
+    splitPane.removeFocusListener(focusListener);
+
+    focusListener = null;
+    propertyChangeListener = null;
+  }
+
+  /**
+   * Returns the input map for the specified condition.
+   * 
+   * @param condition  the condition.
+   * 
+   * @return The input map.
+   */
+  InputMap getInputMap(int condition) 
+  {
+    if (condition == JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT)
+      return (InputMap) UIManager.get("SplitPane.ancestorInputMap");
+    return null;
+  }
+
+  /**
+   * Returns the action map for the {@link JSplitPane}.  All sliders share
+   * a single action map which is created the first time this method is 
+   * called, then stored in the UIDefaults table for subsequent access.
+   * 
+   * @return The shared action map.
+   */
+  ActionMap getActionMap() 
+  {
+    ActionMap map = (ActionMap) UIManager.get("SplitPane.actionMap");
+
+    if (map == null) // first time here
+      {
+        map = createActionMap();
+        if (map != null)
+          UIManager.put("SplitPane.actionMap", map);
+      }
+    return map;
+  }
+
+  /**
+   * Creates the action map shared by all {@link JSlider} instances.
+   * This method is called once by {@link #getActionMap()} when it 
+   * finds no action map in the UIDefaults table...after the map is 
+   * created, it gets added to the defaults table so that subsequent 
+   * calls to {@link #getActionMap()} will return the same shared 
+   * instance.
+   * 
+   * @return The action map.
+   */
+  ActionMap createActionMap()
+  {
+    ActionMap map = new ActionMapUIResource();
+    map.put("toggleFocus", 
+            new AbstractAction("toggleFocus") {
+              public void actionPerformed(ActionEvent event)
+              {
+                // FIXME: What to do here?
+              }
+            }
+    );
+    map.put("startResize", 
+            new AbstractAction("startResize") {
+              public void actionPerformed(ActionEvent event)
+              {
+                splitPane.requestFocus();
+              }
+            }
+    );
+    map.put("selectMax", 
+            new AbstractAction("selectMax") {
+              public void actionPerformed(ActionEvent event)
+              {
+                splitPane.setDividerLocation(1.0);
+              }
+            }
+    );
+    map.put("selectMin", 
+            new AbstractAction("selectMin") {
+              public void actionPerformed(ActionEvent event)
+              {
+                splitPane.setDividerLocation(0.0);
+              }
+            }
+    );
+    map.put("negativeIncrement", 
+            new AbstractAction("negativeIncrement") {
+              public void actionPerformed(ActionEvent event)
+              {
+                setDividerLocation(splitPane, Math.max(dividerLocation 
+                    - KEYBOARD_DIVIDER_MOVE_OFFSET, 0));
+              }
+            }
+    );
+    map.put("positiveIncrement", 
+            new AbstractAction("positiveIncrement") {
+              public void actionPerformed(ActionEvent event)
+              {
+                setDividerLocation(splitPane, dividerLocation 
+                    + KEYBOARD_DIVIDER_MOVE_OFFSET);
+              }
+            }
+    );
+    map.put("focusOutBackward",
+            new AbstractAction("focusOutBackward") {
+              public void actionPerformed(ActionEvent event)
+              {
+                // FIXME: implement this
+              }
+            }
+    );    
+    map.put("focusOutForward",
+            new AbstractAction("focusOutForward") {
+              public void actionPerformed(ActionEvent event)
+              {
+                // FIXME: implement this
+              }
+            }
+    );    
+    return map;
+  }
+
+  /**
+   * Installs any keyboard actions. The list of keys that need to be bound are
+   * listed in Basic look and feel's defaults.
+   */
+  protected void installKeyboardActions()
+  {
+    InputMap keyMap = getInputMap(
+        JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
+    SwingUtilities.replaceUIInputMap(splitPane, 
+        JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT, keyMap);
+    ActionMap map = getActionMap();
+    SwingUtilities.replaceUIActionMap(splitPane, map);
+  }
+
+  /**
+   * This method reverses the work done in installKeyboardActions.
+   */
+  protected void uninstallKeyboardActions()
+  {
+    SwingUtilities.replaceUIActionMap(splitPane, null);
+    SwingUtilities.replaceUIInputMap(splitPane, 
+        JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT, null);
+  }
+
+  /**
+   * This method creates a new PropertyChangeListener.
+   *
+   * @return A new PropertyChangeListener.
+   */
+  protected PropertyChangeListener createPropertyChangeListener()
+  {
+    return new PropertyHandler();
+  }
+
+  /**
+   * This method creates a new FocusListener.
+   *
+   * @return A new FocusListener.
+   */
+  protected FocusListener createFocusListener()
+  {
+    return new FocusHandler();
+  }
+
+  /**
+   * This method creates a new ActionListener for up and left key presses.
+   *
+   * @return A new ActionListener for up and left keys.
+   *
+   * @deprecated 1.3
+   */
+  protected ActionListener createKeyboardUpLeftListener()
+  {
+    return new KeyboardUpLeftHandler();
+  }
+
+  /**
+   * This method creates a new ActionListener for down and right key presses.
+   *
+   * @return A new ActionListener for down and right keys.
+   *
+   * @deprecated 1.3
+   */
+  protected ActionListener createKeyboardDownRightListener()
+  {
+    return new KeyboardDownRightHandler();
+  }
+
+  /**
+   * This method creates a new ActionListener for home key presses.
+   *
+   * @return A new ActionListener for home keys.
+   *
+   * @deprecated
+   */
+  protected ActionListener createKeyboardHomeListener()
+  {
+    return new KeyboardHomeHandler();
+  }
+
+  /**
+   * This method creates a new ActionListener for end key presses.i
+   *
+   * @return A new ActionListener for end keys.
+   *
+   * @deprecated 1.3
+   */
+  protected ActionListener createKeyboardEndListener()
+  {
+    return new KeyboardEndHandler();
+  }
+
+  /**
+   * This method creates a new ActionListener for resize toggle key events.
+   *
+   * @return A new ActionListener for resize toggle keys.
+   *
+   * @deprecated 1.3
+   */
+  protected ActionListener createKeyboardResizeToggleListener()
+  {
+    return new KeyboardResizeToggleHandler();
+  }
+
+  /**
+   * This method returns the orientation of the JSplitPane.
+   *
+   * @return The orientation of the JSplitPane.
+   */
+  public int getOrientation()
+  {
+    return splitPane.getOrientation();
+  }
+
+  /**
+   * This method sets the orientation of the JSplitPane.
+   *
+   * @param orientation The new orientation of the JSplitPane.
+   */
+  public void setOrientation(int orientation)
+  {
+    splitPane.setOrientation(orientation);
+  }
+
+  /**
+   * This method returns true if the JSplitPane is using continuous layout.
+   *
+   * @return True if the JSplitPane is using continuous layout.
+   */
+  public boolean isContinuousLayout()
+  {
+    return splitPane.isContinuousLayout();
+  }
+
+  /**
+   * This method sets the continuous layout property of the JSplitPane.
+   *
+   * @param b True if the JsplitPane is to use continuous layout.
+   */
+  public void setContinuousLayout(boolean b)
+  {
+    splitPane.setContinuousLayout(b);
+  }
+
+  /**
+   * This method returns the last location the divider was dragged to.
+   *
+   * @return The last location the divider was dragged to.
+   */
+  public int getLastDragLocation()
+  {
+    return lastDragLocation;
+  }
+
+  /**
+   * This method sets the last location the divider was dragged to.
+   *
+   * @param l The last location the divider was dragged to.
+   */
+  public void setLastDragLocation(int l)
+  {
+    lastDragLocation = l;
+  }
+
+  /**
+   * This method returns the BasicSplitPaneDivider that divides this
+   * JSplitPane.
+   *
+   * @return The divider for the JSplitPane.
+   */
+  public BasicSplitPaneDivider getDivider()
+  {
+    return divider;
+  }
+
+  /**
+   * This method creates a nonContinuousLayoutDivider for use with the
+   * JSplitPane in nonContinousLayout mode. The default divider is a gray
+   * Canvas.
+   *
+   * @return The default nonContinousLayoutDivider.
+   */
+  protected Component createDefaultNonContinuousLayoutDivider()
+  {
+    if (nonContinuousLayoutDivider == null)
+      {
+        nonContinuousLayoutDivider = new Canvas();
+        Color c = UIManager.getColor("SplitPaneDivider.draggingColor");
+        nonContinuousLayoutDivider.setBackground(c);
+      }
+    return nonContinuousLayoutDivider;
+  }
+
+  /**
+   * This method sets the component to use as the nonContinuousLayoutDivider.
+   *
+   * @param newDivider The component to use as the nonContinuousLayoutDivider.
+   */
+  protected void setNonContinuousLayoutDivider(Component newDivider)
+  {
+    setNonContinuousLayoutDivider(newDivider, true);
+  }
+
+  /**
+   * This method sets the component to use as the nonContinuousLayoutDivider.
+   *
+   * @param newDivider The component to use as the nonContinuousLayoutDivider.
+   * @param rememberSizes FIXME: document.
+   */
+  protected void setNonContinuousLayoutDivider(Component newDivider,
+                                               boolean rememberSizes)
+  {
+    // FIXME: use rememberSizes for something
+    nonContinuousLayoutDivider = newDivider;
+  }
+
+  /**
+   * This method returns the nonContinuousLayoutDivider.
+   *
+   * @return The nonContinuousLayoutDivider.
+   */
+  public Component getNonContinuousLayoutDivider()
+  {
+    return nonContinuousLayoutDivider;
+  }
+
+  /**
+   * This method returns the JSplitPane that this BasicSplitPaneUI draws.
+   *
+   * @return The JSplitPane.
+   */
+  public JSplitPane getSplitPane()
+  {
+    return splitPane;
+  }
+
+  /**
+   * This method creates the divider used normally with the JSplitPane.
+   *
+   * @return The default divider.
+   */
+  public BasicSplitPaneDivider createDefaultDivider()
+  {
+    if (divider == null)
+      divider = new BasicSplitPaneDivider(this);
+    return divider;
+  }
+
+  /**
+   * This method is called when JSplitPane's resetToPreferredSizes is called.
+   * It resets the sizes of all components in the JSplitPane.
+   *
+   * @param jc The JSplitPane to reset.
+   */
+  public void resetToPreferredSizes(JSplitPane jc)
+  {
+    layoutManager.resetToPreferredSizes();
+  }
+
+  /**
+   * This method sets the location of the divider.
+   *
+   * @param jc The JSplitPane to set the divider location in.
+   * @param location The new location of the divider.
+   */
+  public void setDividerLocation(JSplitPane jc, int location)
+  {
+    dividerLocation = location;
+    splitPane.revalidate();
+    splitPane.repaint();
+  }
+
+  /**
+   * This method returns the location of the divider.
+   *
+   * @param jc The JSplitPane to retrieve the location for.
+   *
+   * @return The location of the divider.
+   */
+  public int getDividerLocation(JSplitPane jc)
+  {
+    return dividerLocation;
+  }
+
+  /**
+   * This method returns the smallest value possible for the location of the
+   * divider.
+   *
+   * @param jc The JSplitPane.
+   *
+   * @return The minimum divider location.
+   */
+  public int getMinimumDividerLocation(JSplitPane jc)
+  {
+    int value = layoutManager.getInitialLocation(jc.getInsets());
+    if (layoutManager.components[0] != null)
+      value += layoutManager.minimumSizeOfComponent(0);
+    return value;
+  }
+
+  /**
+   * This method returns the largest value possible for the location of the
+   * divider.
+   *
+   * @param jc The JSplitPane.
+   *
+   * @return The maximum divider location.
+   */
+  public int getMaximumDividerLocation(JSplitPane jc)
+  {
+    int value = layoutManager.getInitialLocation(jc.getInsets())
+                + layoutManager.getAvailableSize(jc.getSize(), jc.getInsets())
+                - splitPane.getDividerSize();
+    if (layoutManager.components[1] != null)
+      value -= layoutManager.minimumSizeOfComponent(1);
+    return value;
+  }
+
+  /**
+   * This method is called after the children of the JSplitPane are painted.
+   *
+   * @param jc The JSplitPane.
+   * @param g The Graphics object to paint with.
+   */
+  public void finishedPaintingChildren(JSplitPane jc, Graphics g)
+  {
+    if (! splitPane.isContinuousLayout() && nonContinuousLayoutDivider != null
+        && nonContinuousLayoutDivider.isVisible())
+      javax.swing.SwingUtilities.paintComponent(g, nonContinuousLayoutDivider,
+                                                null,
+                                                nonContinuousLayoutDivider
+                                                .getBounds());
+  }
+
+  /**
+   * This method is called to paint the JSplitPane.
+   *
+   * @param g The Graphics object to paint with.
+   * @param jc The JSplitPane to paint.
+   */
+  public void paint(Graphics g, JComponent jc)
+  {
+    // TODO: What should be done here?
+  }
+
+  /**
+   * This method returns the preferred size of the JSplitPane.
+   *
+   * @param jc The JSplitPane.
+   *
+   * @return The preferred size of the JSplitPane.
+   */
+  public Dimension getPreferredSize(JComponent jc)
+  {
+    return layoutManager.preferredLayoutSize((Container) jc);
+  }
+
+  /**
+   * This method returns the minimum size of the JSplitPane.
+   *
+   * @param jc The JSplitPane.
+   *
+   * @return The minimum size of the JSplitPane.
+   */
+  public Dimension getMinimumSize(JComponent jc)
+  {
+    return layoutManager.minimumLayoutSize((Container) jc);
+  }
+
+  /**
+   * This method returns the maximum size of the JSplitPane.
+   *
+   * @param jc The JSplitPane.
+   *
+   * @return The maximum size of the JSplitPane.
+   */
+  public Dimension getMaximumSize(JComponent jc)
+  {
+    return layoutManager.maximumLayoutSize((Container) jc);
+  }
+
+  /**
+   * This method returns the border insets of the current border.
+   *
+   * @param jc The JSplitPane.
+   *
+   * @return The current border insets.
+   */
+  public Insets getInsets(JComponent jc)
+  {
+    return splitPane.getBorder().getBorderInsets(splitPane);
+  }
+
+  /**
+   * This method resets the current layout manager. The type of layout manager
+   * is dependent on the current orientation.
+   */
+  protected void resetLayoutManager()
+  {
+    if (getOrientation() == JSplitPane.HORIZONTAL_SPLIT)
+      layoutManager = new BasicHorizontalLayoutManager();
+    else
+      layoutManager = new BasicVerticalLayoutManager();
+    getSplitPane().setLayout(layoutManager);
+    layoutManager.updateComponents();
+
+    // invalidating by itself does not invalidate the layout.
+    getSplitPane().revalidate();
+  }
+
+  /**
+   * This method is called when dragging starts. It resets lastDragLocation
+   * and dividerSize.
+   */
+  protected void startDragging()
+  {
+    Component left = splitPane.getLeftComponent();
+    Component right = splitPane.getRightComponent();
+    dividerSize = divider.getDividerSize();
+    setLastDragLocation(-1);
+
+    if ((left != null && !left.isLightweight())
+        || (right != null && !right.isLightweight()))
+      draggingHW = true;
+
+    if (splitPane.isContinuousLayout())
+      nonContinuousLayoutDivider.setVisible(false);
+    else
+      {
+        nonContinuousLayoutDivider.setVisible(true);
+        nonContinuousLayoutDivider.setBounds(divider.getBounds());
+      }
+  }
+
+  /**
+   * This method is called whenever the divider is dragged. If the JSplitPane
+   * is in continuousLayout mode, the divider needs to be moved and the
+   * JSplitPane needs to be laid out.
+   *
+   * @param location The new location of the divider.
+   */
+  protected void dragDividerTo(int location)
+  {
+    location = validLocation(location);
+    if (beginDragDividerLocation == -1)
+      beginDragDividerLocation = location;
+
+    if (splitPane.isContinuousLayout())
+      splitPane.setDividerLocation(location);
+    else
+      {
+        Point p = nonContinuousLayoutDivider.getLocation();
+        if (getOrientation() == JSplitPane.HORIZONTAL_SPLIT)
+          p.x = location;
+        else
+          p.y = location;
+        nonContinuousLayoutDivider.setLocation(p);
+      }
+    setLastDragLocation(location);
+    splitPane.repaint();
+  }
+
+  /**
+   * This method is called when the dragging is finished.
+   *
+   * @param location The location where the drag finished.
+   */
+  protected void finishDraggingTo(int location)
+  {
+    if (nonContinuousLayoutDivider != null)
+      nonContinuousLayoutDivider.setVisible(false);
+    draggingHW = false;
+    location = validLocation(location);
+    splitPane.setDividerLocation(location);
+    splitPane.setLastDividerLocation(beginDragDividerLocation);
+    beginDragDividerLocation = -1;
+  }
+
+  /**
+   * This method returns the width of one of the sides of the divider's border.
+   *
+   * @return The width of one side of the divider's border.
+   *
+   * @deprecated 1.3
+   */
+  protected int getDividerBorderSize()
+  {
+    if (getOrientation() == JSplitPane.HORIZONTAL_SPLIT)
+      return divider.getBorder().getBorderInsets(divider).left;
+    else
+      return divider.getBorder().getBorderInsets(divider).top;
+  }
+
+  /**
+   * This is a helper method that returns a valid location for the divider
+   * when dragging.
+   *
+   * @param location The location to check.
+   *
+   * @return A valid location.
+   */
+  private int validLocation(int location)
+  {
+    int min = getMinimumDividerLocation(splitPane);
+    int max = getMaximumDividerLocation(splitPane);
+    if (min > 0 && location < min)
+      return min;
+    if (max > 0 && location > max)
+      return max;
+    return location;
+  }
+}

Added: llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/BasicTabbedPaneUI.java
URL: http://llvm.org/viewvc/llvm-project/llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/BasicTabbedPaneUI.java?rev=43913&view=auto

==============================================================================
--- llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/BasicTabbedPaneUI.java (added)
+++ llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/BasicTabbedPaneUI.java Thu Nov  8 16:56:19 2007
@@ -0,0 +1,3880 @@
+/* BasicTabbedPaneUI.java --
+   Copyright (C) 2002, 2004, 2005, 2006  Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package javax.swing.plaf.basic;
+
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Container;
+import java.awt.Dimension;
+import java.awt.Font;
+import java.awt.FontMetrics;
+import java.awt.Graphics;
+import java.awt.Insets;
+import java.awt.LayoutManager;
+import java.awt.Point;
+import java.awt.Rectangle;
+import java.awt.event.ActionEvent;
+import java.awt.event.FocusAdapter;
+import java.awt.event.FocusEvent;
+import java.awt.event.FocusListener;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseListener;
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+
+import javax.swing.AbstractAction;
+import javax.swing.ActionMap;
+import javax.swing.Icon;
+import javax.swing.InputMap;
+import javax.swing.JComponent;
+import javax.swing.JPanel;
+import javax.swing.JTabbedPane;
+import javax.swing.JViewport;
+import javax.swing.KeyStroke;
+import javax.swing.LookAndFeel;
+import javax.swing.SwingConstants;
+import javax.swing.SwingUtilities;
+import javax.swing.UIManager;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+import javax.swing.plaf.ActionMapUIResource;
+import javax.swing.plaf.ComponentUI;
+import javax.swing.plaf.PanelUI;
+import javax.swing.plaf.TabbedPaneUI;
+import javax.swing.plaf.UIResource;
+import javax.swing.text.View;
+
+/**
+ * This is the Basic Look and Feel's UI delegate for JTabbedPane.
+ * 
+ * @author Lillian Angel (langel at redhat.com)
+ * @author Kim Ho (kho at redhat.com)
+ * @author Roman Kennke (kennke at aicas.com)
+ * @author Robert Schuster (robertschuster at fsfe.org)
+ */
+public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
+{
+  
+  static class NavigateAction extends AbstractAction
+  {
+    int direction;
+    
+    NavigateAction(String name, int dir)
+    {
+      super(name);
+      direction = dir;
+    }
+
+    public void actionPerformed(ActionEvent event)
+    {
+      JTabbedPane tp = (JTabbedPane) event.getSource();
+      BasicTabbedPaneUI ui = (BasicTabbedPaneUI) tp.getUI();
+
+      ui.navigateSelectedTab(direction);
+    }
+  
+  }
+  
+  static class NavigatePageDownAction extends AbstractAction
+  {
+
+    public NavigatePageDownAction()
+    {
+      super("navigatePageDown");
+    }
+
+    public void actionPerformed(ActionEvent event)
+    {
+      JTabbedPane tp = (JTabbedPane) event.getSource();
+      BasicTabbedPaneUI ui = (BasicTabbedPaneUI) tp.getUI();
+      
+      int i = tp.getSelectedIndex();
+      
+      if (i < 0)
+        i = 0;
+      
+      ui.selectNextTabInRun(i);
+    }
+    
+  }
+  
+  static class NavigatePageUpAction extends AbstractAction
+  {
+
+    public NavigatePageUpAction()
+    {
+      super("navigatePageUp");
+    }
+
+    public void actionPerformed(ActionEvent event)
+    {
+      JTabbedPane tp = (JTabbedPane) event.getSource();
+      BasicTabbedPaneUI ui = (BasicTabbedPaneUI) tp.getUI();
+      
+      int i = tp.getSelectedIndex();
+      
+      if (i < 0)
+        i = 0;
+      
+      ui.selectPreviousTabInRun(i);
+
+    }    
+  }
+  
+  static class RequestFocusAction extends AbstractAction
+  {
+
+    public RequestFocusAction()
+    {
+      super("requestFocus");
+    }
+
+    public void actionPerformed(ActionEvent event)
+    {
+      ((JTabbedPane) event.getSource()).requestFocus();
+    }
+    
+  }
+
+  static class RequestFocusForVisibleComponentAction extends AbstractAction
+  {
+
+    public RequestFocusForVisibleComponentAction()
+    {
+      super("requestFocusForVisibleComponent");
+    }
+
+    public void actionPerformed(ActionEvent event)
+    {
+      JTabbedPane tp = (JTabbedPane) event.getSource();
+      
+      // FIXME: This should select a suitable component within
+      // the tab content. However I dont know whether we have
+      // to search for this component or wether the called is
+      // supposed to do that.
+      tp.getSelectedComponent().requestFocus();
+    }
+    
+  }
+
+  /**
+   * A helper class that handles focus. 
+   * <p>The purpose of this class is to implement a more flexible focus
+   * handling for the tabbed pane, which is used to determine whether the
+   * focus indicator should be painted or not. When in scrolling layout
+   * mode the area containing the tabs is a scrollpane, so simply testing
+   * whether the tabbed pane has the focus does not work.</p>
+   * <p>The <code>FocusHandler</code> is installed on the scrollpane and
+   * the tabbed pane and sets the variable <code>hasFocus</code> to
+   * <code>false</code> only when both components do not hold the focus.</p>
+   *
+   * @specnote Apparently this class was intended to be protected,
+   *           but was made public by a compiler bug and is now
+   *           public for compatibility.
+   */
+  public class FocusHandler extends FocusAdapter
+  {
+    /**
+     * This method is called when the component gains focus.
+     *
+     * @param e The FocusEvent.
+     */
+    public void focusGained(FocusEvent e)
+    {
+      Object source = e.getSource();
+      if (source == panel )
+        tabPane.requestFocus();
+      else if (source == tabPane)
+        tabPane.repaint();
+    }
+
+    /**
+     * This method is called when the component loses focus.
+     *
+     * @param e The FocusEvent.
+     */
+    public void focusLost(FocusEvent e)
+    {
+      if (e.getOppositeComponent() == tabPane.getSelectedComponent())
+        tabPane.requestFocus();
+      else if (e.getSource() == tabPane)
+        tabPane.repaint();
+    }
+  }
+
+  /**
+   * A helper class for determining if mouse presses occur inside tabs and
+   * sets the index appropriately. In SCROLL_TAB_MODE, this class also
+   * handles the mouse clicks on the scrolling buttons.
+   *
+   * @specnote Apparently this class was intended to be protected,
+   *           but was made public by a compiler bug and is now
+   *           public for compatibility.
+   */
+  public class MouseHandler extends MouseAdapter
+  {
+    public void mouseReleased(MouseEvent e)
+    {
+     // Nothing to do here. 
+    }
+    
+    /**
+     * This method is called when the mouse is pressed. The index cannot
+     * change to a tab that is  not enabled.
+     *
+     * @param e The MouseEvent.
+     */
+    public void mousePressed(MouseEvent e)
+    {
+      Object s = e.getSource();
+      int placement = tabPane.getTabPlacement();
+    
+      if (s == incrButton)
+        {
+          if(!incrButton.isEnabled())
+            return;
+
+          currentScrollLocation++;
+
+          switch (placement)
+            {
+              case JTabbedPane.TOP:
+              case JTabbedPane.BOTTOM: 
+                currentScrollOffset = getTabAreaInsets(placement).left;
+                for (int i = 0; i < currentScrollLocation; i++)
+                  currentScrollOffset += rects[i].width;
+                break;
+              default:
+                currentScrollOffset = getTabAreaInsets(placement).top;
+                for (int i = 0; i < currentScrollLocation; i++)
+                  currentScrollOffset += rects[i].height;
+                break;
+            }
+            
+          updateViewPosition();
+          updateButtons();
+        
+          tabPane.repaint();
+        }
+      else if (s == decrButton)
+        {
+          if(!decrButton.isEnabled())
+            return;
+        
+          // The scroll location may be zero but the offset
+          // greater than zero because of an adjustement to
+          // make a partially visible tab completely visible.
+          if (currentScrollLocation > 0)
+            currentScrollLocation--;
+        
+          // Set the offset back to 0 and recompute it.
+          currentScrollOffset = 0;
+
+          switch (placement)
+            {
+              case JTabbedPane.TOP:
+              case JTabbedPane.BOTTOM: 
+                // Take the tab area inset into account.
+                if (currentScrollLocation > 0)
+                  currentScrollOffset = getTabAreaInsets(placement).left;
+                // Recompute scroll offset.
+        for (int i = 0; i < currentScrollLocation; i++)
+          currentScrollOffset += rects[i].width;
+        break;
+        default:
+          // Take the tab area inset into account.
+          if (currentScrollLocation > 0)
+            currentScrollOffset = getTabAreaInsets(placement).top;
+        
+          for (int i = 0; i < currentScrollLocation; i++)
+            currentScrollOffset += rects[i].height;
+        }          
+        
+       updateViewPosition();
+       updateButtons();
+        
+       tabPane.repaint();
+      } else if (tabPane.isEnabled())
+        {
+          int index = tabForCoordinate(tabPane, e.getX(), e.getY());
+          if (tabPane.getTabLayoutPolicy() == JTabbedPane.SCROLL_TAB_LAYOUT
+              && s == panel)
+              scrollTab(index, placement);
+          
+          tabPane.setSelectedIndex(index);
+        }
+      
+    }
+
+    /**
+     * Receives notification when the mouse pointer has entered the tabbed
+     * pane.
+     *
+     * @param ev the mouse event
+     */
+    public void mouseEntered(MouseEvent ev)
+    {
+      int tabIndex = tabForCoordinate(tabPane, ev.getX(), ev.getY());
+      setRolloverTab(tabIndex);
+    }
+
+    /**
+     * Receives notification when the mouse pointer has exited the tabbed
+     * pane.
+     *
+     * @param ev the mouse event
+     */
+    public void mouseExited(MouseEvent ev)
+    {
+      setRolloverTab(-1);
+    }
+
+    /**
+     * Receives notification when the mouse pointer has moved over the tabbed
+     * pane.
+     *
+     * @param ev the mouse event
+     */
+    public void mouseMoved(MouseEvent ev)
+    {
+      int tabIndex = tabForCoordinate(tabPane, ev.getX(), ev.getY());
+      setRolloverTab(tabIndex);
+    }
+  }
+
+  /**
+   * This class handles PropertyChangeEvents fired from the JTabbedPane.
+   *
+   * @specnote Apparently this class was intended to be protected,
+   *           but was made public by a compiler bug and is now
+   *           public for compatibility.
+   */
+  public class PropertyChangeHandler implements PropertyChangeListener
+  {
+    /**
+     * This method is called whenever one of the properties of the JTabbedPane
+     * changes.
+     *
+     * @param e The PropertyChangeEvent.
+     */
+    public void propertyChange(PropertyChangeEvent e)
+    {
+      if (e.getPropertyName().equals("tabLayoutPolicy"))
+        {
+          currentScrollLocation = currentScrollOffset = 0;
+          
+          layoutManager = createLayoutManager();
+          
+          tabPane.setLayout(layoutManager);
+        }
+      else if (e.getPropertyName().equals("tabPlacement")
+          && tabPane.getTabLayoutPolicy() == JTabbedPane.SCROLL_TAB_LAYOUT)
+        {
+          incrButton = createIncreaseButton();
+          decrButton = createDecreaseButton();
+        }
+      tabPane.revalidate();
+      tabPane.repaint();
+    }
+  }
+
+  /**
+   * A LayoutManager responsible for placing all the tabs and the visible
+   * component inside the JTabbedPane. This class is only used for
+   * WRAP_TAB_LAYOUT.
+   *
+   * @specnote Apparently this class was intended to be protected,
+   *           but was made public by a compiler bug and is now
+   *           public for compatibility.
+   */
+  public class TabbedPaneLayout implements LayoutManager
+  {
+    /**
+     * This method is called when a component is added to the JTabbedPane.
+     *
+     * @param name The name of the component.
+     * @param comp The component being added.
+     */
+    public void addLayoutComponent(String name, Component comp)
+    {
+      // Do nothing.
+    }
+
+    /**
+     * This method is called when the rectangles need to be calculated. It
+     * also fixes the size of the visible component.
+     */
+    public void calculateLayoutInfo()
+    {
+      int count = tabPane.getTabCount();
+      assureRectsCreated(count);
+      calculateTabRects(tabPane.getTabPlacement(), count);
+      tabRunsDirty = false;
+    }
+
+    /**
+     * This method calculates the size of the the JTabbedPane.
+     *
+     * @param minimum Whether the JTabbedPane will try to be as small as it
+     *        can.
+     *
+     * @return The desired size of the JTabbedPane.
+     */
+    protected Dimension calculateSize(boolean minimum)
+    {
+      int tabPlacement = tabPane.getTabPlacement();
+
+      int width = 0;
+      int height = 0;
+      Component c;
+      Dimension dims;
+
+      // Find out the minimum/preferred size to display the largest child
+      // of the tabbed pane.
+      int count = tabPane.getTabCount();
+      for (int i = 0; i < count; i++)
+        {
+          c = tabPane.getComponentAt(i);
+          if (c == null)
+            continue;
+          dims = minimum ? c.getMinimumSize() : c.getPreferredSize(); 
+          if (dims != null)
+            {
+              height = Math.max(height, dims.height);
+              width = Math.max(width, dims.width);
+            }
+        }
+
+      Insets tabAreaInsets = getTabAreaInsets(tabPlacement);
+      if (tabPlacement == SwingConstants.TOP
+          || tabPlacement == SwingConstants.BOTTOM)
+        {
+          width = Math.max(calculateMaxTabWidth(tabPlacement), width);
+          
+          height += preferredTabAreaHeight(tabPlacement,
+                                           width - tabAreaInsets.left
+                                           - tabAreaInsets.right);
+        }
+      else
+        {
+          height = Math.max(calculateMaxTabHeight(tabPlacement), height);
+          
+          width += preferredTabAreaWidth(tabPlacement,
+                                         height - tabAreaInsets.top
+                                         - tabAreaInsets.bottom);
+        }
+
+      Insets tabPaneInsets = tabPane.getInsets();
+      return new Dimension(width + tabPaneInsets.left + tabPaneInsets.right,
+                           height + tabPaneInsets.top + tabPaneInsets.bottom);
+    }
+
+    // if tab placement is LEFT OR RIGHT, they share width.
+    // if tab placement is TOP OR BOTTOM, they share height
+    // PRE STEP: finds the default sizes for the labels as well as their
+    // locations.
+    // AND where they will be placed within the run system.
+    // 1. calls normalizeTab Runs.
+    // 2. calls rotate tab runs.
+    // 3. pads the tab runs.
+    // 4. pads the selected tab.
+
+    /**
+     * This method is called to calculate the tab rectangles.  This method
+     * will calculate the size and position of all  rectangles (taking into
+     * account which ones should be in which tab run). It will pad them and
+     * normalize them  as necessary.
+     *
+     * @param tabPlacement The JTabbedPane's tab placement.
+     * @param tabCount The run the current selection is in.
+     */
+    protected void calculateTabRects(int tabPlacement, int tabCount)
+    {
+      Insets insets = tabPane.getInsets();
+      Insets tabAreaInsets = getTabAreaInsets(tabPlacement);
+      Dimension size = tabPane.getSize();
+      
+      // The coordinates of the upper left corner of the tab area.
+      int x;
+      int y;
+      // The location at which the runs must be broken.
+      int breakAt;
+
+      // Calculate the bounds for the tab area.
+      switch (tabPlacement)
+      {
+        case LEFT:
+          maxTabWidth = calculateMaxTabWidth(tabPlacement);
+          x = insets.left + tabAreaInsets.left;
+          y = insets.top + tabAreaInsets.top;
+          breakAt = size.height - (insets.bottom + tabAreaInsets.bottom);
+          break;
+        case RIGHT:
+          maxTabWidth = calculateMaxTabWidth(tabPlacement);
+          x = size.width - (insets.right + tabAreaInsets.right)
+              - maxTabWidth - 1;
+          y = insets.top + tabAreaInsets.top;
+          breakAt = size.height - (insets.bottom + tabAreaInsets.bottom);
+          break;
+        case BOTTOM:
+          maxTabHeight = calculateMaxTabHeight(tabPlacement);
+          x = insets.left + tabAreaInsets.left;
+          y = size.height - (insets.bottom + tabAreaInsets.bottom)
+              - maxTabHeight - 1;
+          breakAt = size.width - (insets.right + tabAreaInsets.right);
+          break;
+        case TOP:
+        default:
+          maxTabHeight = calculateMaxTabHeight(tabPlacement);
+          x = insets.left + tabAreaInsets.left;
+          y = insets.top + tabAreaInsets.top;
+          breakAt = size.width - (insets.right + tabAreaInsets.right);
+          break;
+      }
+
+      if (tabCount == 0)
+        return;
+
+      FontMetrics fm = getFontMetrics();
+      runCount = 0;
+      selectedRun = -1;
+      int selectedIndex = tabPane.getSelectedIndex();
+      if (selectedIndex < 0)
+          selectedIndex = 0;
+
+      Rectangle rect;
+
+      // Go through all the tabs and build the tab runs.
+      if (tabPlacement == SwingConstants.TOP
+          || tabPlacement == SwingConstants.BOTTOM)
+        {
+          for (int i = 0; i < tabCount; i++)
+            {
+              rect = rects[i];
+              if (i > 0)
+                {
+                  rect.x = rects[i - 1].x + rects[i - 1].width;
+                }
+              else
+                {
+                  tabRuns[0] = 0;
+                  runCount = 1;
+                  maxTabWidth = 0;
+                  rect.x = x;
+                }
+              rect.width = calculateTabWidth(tabPlacement, i, fm);
+              maxTabWidth = Math.max(maxTabWidth, rect.width);
+
+              if (rect.x != 2 + insets.left && rect.x + rect.width > breakAt)
+                {
+                  if (runCount > tabRuns.length - 1)
+                    expandTabRunsArray();
+                  tabRuns[runCount] = i;
+                  runCount++;
+                  rect.x = x;
+                }
+
+              rect.y = y;
+              rect.height = maxTabHeight;
+              if (i == selectedIndex)
+                selectedRun = runCount - 1;
+            }
+        }
+      else
+        {
+          for (int i = 0; i < tabCount; i++)
+            {
+              rect = rects[i];
+              if (i > 0)
+                {
+                  rect.y = rects[i - 1].y + rects[i - 1].height;
+                }
+              else
+                {
+                  tabRuns[0] = 0;
+                  runCount = 1;
+                  maxTabHeight = 0;
+                  rect.y = y;
+                }
+              rect.height = calculateTabHeight(tabPlacement, i,
+                                               fm.getHeight());
+              maxTabHeight = Math.max(maxTabHeight, rect.height);
+
+              if (rect.y != 2 + insets.top && rect.y + rect.height > breakAt)
+                {
+                  if (runCount > tabRuns.length - 1)
+                    expandTabRunsArray();
+                  tabRuns[runCount] = i;
+                  runCount++;
+                  rect.y = y;
+                }
+
+              rect.x = x;
+              rect.width = maxTabWidth;
+
+              if (i == selectedIndex)
+                selectedRun = runCount - 1;
+            }
+        }
+
+      if (runCount > 1)
+        {
+          int start;
+          if  (tabPlacement == SwingConstants.TOP
+              || tabPlacement == SwingConstants.BOTTOM)
+            start = x;
+          else
+            start = y;
+          normalizeTabRuns(tabPlacement, tabCount, start, breakAt);
+          selectedRun = getRunForTab(tabCount, selectedIndex);
+          if (shouldRotateTabRuns(tabPlacement))
+            {
+              rotateTabRuns(tabPlacement, selectedRun);
+            }
+        }
+      
+      // Suppress padding if we have only one tab run.
+      if (runCount == 1)
+        return;
+      
+      // Pad the runs.
+      int tabRunOverlay = getTabRunOverlay(tabPlacement);
+      for (int i = runCount - 1; i >= 0; --i)
+        {
+          int start = tabRuns[i];
+          int nextIndex;
+          if (i == runCount - 1)
+            nextIndex = 0;
+          else
+            nextIndex = i + 1;
+          int next = tabRuns[nextIndex];
+          int end = next != 0 ? next - 1 : tabCount - 1;
+          if (tabPlacement == SwingConstants.TOP
+              || tabPlacement == SwingConstants.BOTTOM)
+            {
+              for (int j = start; j <= end; ++j)
+                {
+                  rect = rects[j];
+                  rect.y = y;
+                  rect.x += getTabRunIndent(tabPlacement, i);
+                }
+              if (shouldPadTabRun(tabPlacement, i))
+                {
+                  padTabRun(tabPlacement, start, end, breakAt);
+                }
+              if (tabPlacement == BOTTOM)
+                y -= maxTabHeight - tabRunOverlay;
+              else
+                y += maxTabHeight - tabRunOverlay;
+            }
+          else
+            {
+              for (int j = start; j <= end; ++j)
+                {
+                  rect = rects[j];
+                  rect.x = x;
+                  rect.y += getTabRunIndent(tabPlacement, i);
+                }
+              if (shouldPadTabRun(tabPlacement, i))
+                {
+                  padTabRun(tabPlacement, start, end, breakAt);
+                }
+              if (tabPlacement == RIGHT)
+                x -= maxTabWidth - tabRunOverlay;
+              else
+                x += maxTabWidth - tabRunOverlay;
+              
+            }
+        }
+      padSelectedTab(tabPlacement, selectedIndex);
+    }
+
+    /**
+     * This method is called when the JTabbedPane is laid out in
+     * WRAP_TAB_LAYOUT. It calls calculateLayoutInfo to  find the positions
+     * of all its components.
+     *
+     * @param parent The Container to lay out.
+     */
+    public void layoutContainer(Container parent)
+    {
+      calculateLayoutInfo();
+
+      int tabPlacement = tabPane.getTabPlacement();
+      Insets insets = tabPane.getInsets();
+
+      int selectedIndex = tabPane.getSelectedIndex();
+      
+      Component selectedComponent = null;
+      if (selectedIndex >= 0)
+        selectedComponent = tabPane.getComponentAt(selectedIndex);
+      // The RI doesn't seem to change the component if the new selected
+      // component == null. This is probably so that applications can add
+      // one single component for every tab. 
+      if (selectedComponent != null)
+        {
+          setVisibleComponent(selectedComponent);
+        }
+
+      int childCount = tabPane.getComponentCount();
+      if (childCount > 0)
+        {
+          int compX;
+          int compY;
+          int tabAreaWidth = 0;
+          int tabAreaHeight = 0;
+          switch (tabPlacement)
+          {
+            case LEFT:
+              tabAreaWidth = calculateTabAreaWidth(tabPlacement, runCount,
+                                                   maxTabWidth);
+              compX = tabAreaWidth + insets.left + contentBorderInsets.left;
+              compY = insets.top + contentBorderInsets.top;
+              break;
+            case RIGHT:
+              tabAreaWidth = calculateTabAreaWidth(tabPlacement, runCount,
+                                                   maxTabWidth);
+              compX = insets.left + contentBorderInsets.left;
+              compY = insets.top + contentBorderInsets.top;
+              break;
+            case BOTTOM: 
+              tabAreaHeight = calculateTabAreaHeight(tabPlacement, runCount,
+                                                     maxTabHeight);
+              compX = insets.left + contentBorderInsets.left;
+              compY = insets.top + contentBorderInsets.top;
+              break;
+            case TOP:
+            default:
+              tabAreaHeight = calculateTabAreaHeight(tabPlacement, runCount,
+                                                     maxTabHeight);
+              compX = insets.left + contentBorderInsets.left;
+              compY = tabAreaHeight + insets.top + contentBorderInsets.top;
+          }
+          Rectangle bounds = tabPane.getBounds();
+          int compWidth = bounds.width - tabAreaWidth - insets.left
+                          - insets.right - contentBorderInsets.left
+                          - contentBorderInsets.right;
+          int compHeight = bounds.height - tabAreaHeight - insets.top
+                           - insets.bottom - contentBorderInsets.top
+                           - contentBorderInsets.bottom;
+
+
+          for (int i = 0; i < childCount; ++i)
+            {
+              Component c = tabPane.getComponent(i);
+              c.setBounds(compX, compY, compWidth, compHeight);
+            }
+        }
+    }
+
+    /**
+     * This method returns the minimum layout size for the given container.
+     *
+     * @param parent The container that is being sized.
+     *
+     * @return The minimum size.
+     */
+    public Dimension minimumLayoutSize(Container parent)
+    {
+      return calculateSize(true);
+    }
+
+    // If there is more free space in an adjacent run AND the tab
+    // in the run can fit in the adjacent run, move it. This method
+    // is not perfect, it is merely an approximation.
+    // If you play around with Sun's JTabbedPane, you'll see that 
+    // it does do some pretty strange things with regards to not moving tabs 
+    // that should be moved. 
+    // start = the x position where the tabs will begin
+    // max = the maximum position of where the tabs can go to
+    // (tabAreaInsets.left + the width of the tab area)
+
+    /**
+     * This method tries to "even out" the number of tabs in each run based on
+     * their widths.
+     *
+     * @param tabPlacement The JTabbedPane's tab placement.
+     * @param tabCount The number of tabs.
+     * @param start The x position where the tabs will begin.
+     * @param max The maximum x position where the tab can run to.
+     */
+    protected void normalizeTabRuns(int tabPlacement, int tabCount, int start,
+                                    int max)
+    {
+      Insets tabAreaInsets = getTabAreaInsets(tabPlacement);
+      if (tabPlacement == SwingUtilities.TOP
+          || tabPlacement == SwingUtilities.BOTTOM)
+        {
+          // We should only do this for runCount - 1, cause we can
+          // only shift that many times between runs.
+          for (int i = 1; i < runCount; i++)
+            {
+              Rectangle currRun = rects[lastTabInRun(tabCount, i)];
+              Rectangle nextRun = rects[lastTabInRun(tabCount,
+                                                     getNextTabRun(i))];
+              int spaceInCurr = currRun.x + currRun.width;
+              int spaceInNext = nextRun.x + nextRun.width;
+
+              int diffNow = spaceInCurr - spaceInNext;
+              int diffLater = (spaceInCurr - currRun.width)
+              - (spaceInNext + currRun.width);
+              
+              while (Math.abs(diffLater) < Math.abs(diffNow)
+                  && spaceInNext + currRun.width < max)
+                {
+                  tabRuns[i]--;
+                  spaceInNext += currRun.width;
+                  spaceInCurr -= currRun.width;
+                  currRun = rects[lastTabInRun(tabCount, i)];
+                  diffNow = spaceInCurr - spaceInNext;
+                  diffLater = (spaceInCurr - currRun.width)
+                  - (spaceInNext + currRun.width);
+                }
+              
+              // Fixes the bounds of all tabs in the current
+              // run.
+              int first = tabRuns[i];
+              int last = lastTabInRun(tabCount, i);
+              int currX = start;
+              for (int j = first; j <= last; j++)
+                {
+                  rects[j].x = currX;
+                  currX += rects[j].width;
+                }
+            }
+        }
+      else
+        {
+          for (int i = 1; i < runCount; i++)
+            {
+              Rectangle currRun = rects[lastTabInRun(tabCount, i)];
+              Rectangle nextRun = rects[lastTabInRun(tabCount,
+                                                     getNextTabRun(i))];
+              int spaceInCurr = currRun.y + currRun.height;
+              int spaceInNext = nextRun.y + nextRun.height;
+
+              int diffNow = spaceInCurr - spaceInNext;
+              int diffLater = (spaceInCurr - currRun.height)
+              - (spaceInNext + currRun.height);
+              while (Math.abs(diffLater) < Math.abs(diffNow)
+                  && spaceInNext + currRun.height < max)
+                {
+                  tabRuns[i]--;
+                  spaceInNext += currRun.height;
+                  spaceInCurr -= currRun.height;
+                  currRun = rects[lastTabInRun(tabCount, i)];
+                  diffNow = spaceInCurr - spaceInNext;
+                  diffLater = (spaceInCurr - currRun.height)
+                  - (spaceInNext + currRun.height);
+                }
+
+              // Fixes the bounds of tabs in the current run. 
+              int first = tabRuns[i];
+              int last = lastTabInRun(tabCount, i);
+              int currY = start;
+              for (int j = first; j <= last; j++)
+                {
+                  rects[j].y = currY;
+                  currY += rects[j].height;
+                }
+            }
+        }
+    }
+
+    /**
+     * This method pads the tab at the selected index by the  selected tab pad
+     * insets (so that it looks larger).
+     *
+     * @param tabPlacement The placement of the tabs.
+     * @param selectedIndex The selected index.
+     */
+    protected void padSelectedTab(int tabPlacement, int selectedIndex)
+    {
+      Insets insets = getSelectedTabPadInsets(tabPlacement);
+      rects[selectedIndex].x -= insets.left;
+      rects[selectedIndex].y -= insets.top;
+      rects[selectedIndex].width += insets.left + insets.right;
+      rects[selectedIndex].height += insets.top + insets.bottom;
+    }
+
+    // If the tabs on the run don't fill the width of the window, make it
+    // fit now.
+    // start = starting index of the run
+    // end = last index of the run
+    // max = tabAreaInsets.left + width (or equivalent)
+    // assert start <= end.
+
+    /**
+     * This method makes each tab in the run larger so that the  tabs expand
+     * to fill the runs width/height (depending on tabPlacement).
+     *
+     * @param tabPlacement The placement of the tabs.
+     * @param start The index of the first tab.
+     * @param end The last index of the tab
+     * @param max The amount of space in the run (width for TOP and BOTTOM
+     *        tabPlacement).
+     */
+    protected void padTabRun(int tabPlacement, int start, int end, int max)
+    {
+      if (tabPlacement == SwingConstants.TOP
+          || tabPlacement == SwingConstants.BOTTOM)
+        {
+          int runWidth = rects[end].x + rects[end].width;
+          int spaceRemaining = max - runWidth;
+          int numTabs = end - start + 1;
+          
+          // now divvy up the space.
+          int spaceAllocated = spaceRemaining / numTabs;
+          int currX = rects[start].x;
+          for (int i = start; i <= end; i++)
+            {
+              rects[i].x = currX;
+              rects[i].width += spaceAllocated;
+              
+              currX += rects[i].width;
+              // This is used because since the spaceAllocated 
+              // variable is an int, it rounds down. Sometimes,
+              // we don't fill an entire row, so we make it do
+              // so now.
+              
+              if (i == end && rects[i].x + rects[i].width != max)
+                rects[i].width = max - rects[i].x;
+            }
+        }
+      else
+        {
+          int runHeight = rects[end].y + rects[end].height;
+          int spaceRemaining = max - runHeight;
+          int numTabs = end - start + 1;
+
+          int spaceAllocated = spaceRemaining / numTabs;
+          int currY = rects[start].y;
+          for (int i = start; i <= end; i++)
+            {
+              rects[i].y = currY;
+              rects[i].height += spaceAllocated;
+              currY += rects[i].height;
+              if (i == end && rects[i].y + rects[i].height != max)
+                rects[i].height = max - rects[i].y;
+            }
+        }
+    }
+
+    /**
+     * This method returns the preferred layout size for the given container.
+     *
+     * @param parent The container to size.
+     *
+     * @return The preferred layout size.
+     */
+    public Dimension preferredLayoutSize(Container parent)
+    {
+      return calculateSize(false);
+    }
+
+    /**
+     * This method returns the preferred tab height given a tabPlacement and
+     * width.
+     *
+     * @param tabPlacement The JTabbedPane's tab placement.
+     * @param width The expected width.
+     *
+     * @return The preferred tab area height.
+     */
+    protected int preferredTabAreaHeight(int tabPlacement, int width)
+    {
+      if (tabPane.getTabCount() == 0)
+        return calculateTabAreaHeight(tabPlacement, 0, 0);
+
+      int runs = 0;
+      int runWidth = 0;
+      int tabWidth = 0;
+
+      FontMetrics fm = getFontMetrics();
+
+      Insets tabAreaInsets = getTabAreaInsets(tabPlacement);
+      Insets insets = tabPane.getInsets();
+
+      // Only interested in width, this is a messed up rectangle now.
+      width -= tabAreaInsets.left + tabAreaInsets.right + insets.left
+      + insets.right;
+
+      // The reason why we can't use runCount:
+      // This method is only called to calculate the size request
+      // for the tabbedPane. However, this size request is dependent on
+      // our desired width. We need to find out what the height would
+      // be IF we got our desired width.
+      for (int i = 0; i < tabPane.getTabCount(); i++)
+        {
+          tabWidth = calculateTabWidth(tabPlacement, i, fm);
+          if (runWidth + tabWidth > width)
+            {
+              runWidth = tabWidth;
+              runs++;
+            }
+          else
+            runWidth += tabWidth;
+        }
+      runs++;
+
+      int maxTabHeight = calculateMaxTabHeight(tabPlacement);
+      int tabAreaHeight = calculateTabAreaHeight(tabPlacement, runs,
+                                                 maxTabHeight);
+      return tabAreaHeight;
+    }
+
+    /**
+     * This method calculates the preferred tab area width given a tab
+     * placement and height.
+     *
+     * @param tabPlacement The JTabbedPane's tab placement.
+     * @param height The expected height.
+     *
+     * @return The preferred tab area width.
+     */
+    protected int preferredTabAreaWidth(int tabPlacement, int height)
+    {
+      if (tabPane.getTabCount() == 0)
+        return calculateTabAreaHeight(tabPlacement, 0, 0);
+
+      int runs = 0;
+      int runHeight = 0;
+      int tabHeight = 0;
+
+      FontMetrics fm = getFontMetrics();
+
+      Insets tabAreaInsets = getTabAreaInsets(tabPlacement);
+      Insets insets = tabPane.getInsets();
+
+      height -= tabAreaInsets.top + tabAreaInsets.bottom + insets.top
+      + insets.bottom;
+      int fontHeight = fm.getHeight();
+
+      for (int i = 0; i < tabPane.getTabCount(); i++)
+        {
+          tabHeight = calculateTabHeight(tabPlacement, i, fontHeight);
+          if (runHeight + tabHeight > height)
+            {
+              runHeight = tabHeight;
+              runs++;
+            }
+          else
+            runHeight += tabHeight;
+        }
+      runs++;
+
+      int maxTabWidth = calculateMaxTabWidth(tabPlacement);
+      int tabAreaWidth = calculateTabAreaWidth(tabPlacement, runs,
+                                               maxTabWidth);
+      return tabAreaWidth;
+    }
+
+    /**
+     * This method rotates the places each run in the correct place  the
+     * tabRuns array. See the comment for tabRuns for how the runs are placed
+     * in the array.
+     *
+     * @param tabPlacement The JTabbedPane's tab placement.
+     * @param selectedRun The run the current selection is in.
+     */
+    protected void rotateTabRuns(int tabPlacement, int selectedRun)
+    {
+      if (runCount == 1 || selectedRun == 0 || selectedRun == -1)
+        return;
+      int[] newTabRuns = new int[tabRuns.length];
+      int currentRun = selectedRun;
+      int i = 0;
+      do
+        {
+          newTabRuns[i] = tabRuns[currentRun];
+          currentRun = getNextTabRun(currentRun);
+          i++;
+        }
+      while (i < runCount);
+
+      tabRuns = newTabRuns;
+      BasicTabbedPaneUI.this.selectedRun = 1;
+    }
+
+    /**
+     * This method is called when a component is removed  from the
+     * JTabbedPane.
+     *
+     * @param comp The component removed.
+     */
+    public void removeLayoutComponent(Component comp)
+    {
+      // Do nothing.
+    }
+  }
+
+  /**
+   * This class acts as the LayoutManager for the JTabbedPane in
+   * SCROLL_TAB_MODE.
+   */
+  private class TabbedPaneScrollLayout extends TabbedPaneLayout
+  {
+    /**
+     * This method returns the preferred layout size for the given container.
+     *
+     * @param parent The container to calculate a size for.
+     *
+     * @return The preferred layout size.
+     */
+    public Dimension preferredLayoutSize(Container parent)
+    {
+      return super.calculateSize(false);
+    }
+
+    /**
+     * This method returns the minimum layout size for the given container.
+     *
+     * @param parent The container to calculate a size for.
+     *
+     * @return The minimum layout size.
+     */
+    public Dimension minimumLayoutSize(Container parent)
+    {
+      return super.calculateSize(true);
+    }
+
+    /**
+     * This method calculates the tab area height given  a desired width.
+     *
+     * @param tabPlacement The JTabbedPane's tab placement.
+     * @param width The expected width.
+     *
+     * @return The tab area height given the width.
+     */
+    protected int preferredTabAreaHeight(int tabPlacement, int width)
+    {
+      if (tabPane.getTabCount() == 0)
+        return calculateTabAreaHeight(tabPlacement, 0, 0);
+
+      int runs = 1;
+
+      int maxTabHeight = calculateMaxTabHeight(tabPlacement);
+      int tabAreaHeight = calculateTabAreaHeight(tabPlacement, runs,
+                                                 maxTabHeight);
+      return tabAreaHeight;
+    }
+
+    /**
+     * This method calculates the tab area width given a desired height.
+     *
+     * @param tabPlacement The JTabbedPane's tab placement.
+     * @param height The expected height.
+     *
+     * @return The tab area width given the height.
+     */
+    protected int preferredTabAreaWidth(int tabPlacement, int height)
+    {
+      if (tabPane.getTabCount() == 0)
+        return calculateTabAreaHeight(tabPlacement, 0, 0);
+
+      int runs = 1;
+
+      int maxTabWidth = calculateMaxTabWidth(tabPlacement);
+      int tabAreaWidth = calculateTabAreaWidth(tabPlacement, runs, maxTabWidth);
+      return tabAreaWidth;
+    }
+
+    /**
+     * This method is called to calculate the tab rectangles.  This method
+     * will calculate the size and position of all  rectangles (taking into
+     * account which ones should be in which tab run). It will pad them and
+     * normalize them  as necessary.
+     *
+     * @param tabPlacement The JTabbedPane's tab placement.
+     * @param tabCount The number of tabs.
+     */
+    protected void calculateTabRects(int tabPlacement, int tabCount)
+    {
+      if (tabCount == 0)
+        return;
+
+      FontMetrics fm = getFontMetrics();
+      SwingUtilities.calculateInnerArea(tabPane, calcRect);
+      Insets tabAreaInsets = getTabAreaInsets(tabPlacement);
+      Insets insets = tabPane.getInsets();
+      if (tabPlacement == SwingConstants.TOP
+          || tabPlacement == SwingConstants.BOTTOM)
+        {
+          int maxHeight = calculateMaxTabHeight(tabPlacement);
+          calcRect.width -= tabAreaInsets.left + tabAreaInsets.right;
+          int width = 0;
+          int runWidth = tabAreaInsets.left + insets.left;
+          int top = insets.top + tabAreaInsets.top;
+          for (int i = 0; i < tabCount; i++)
+            {
+              width = calculateTabWidth(tabPlacement, i, fm);
+              
+              // The proper instances should exists because
+              //  assureRectsCreated() was being run already.
+              rects[i].setBounds(runWidth, top, width, maxHeight);
+              
+              runWidth += width;
+            }
+          tabAreaRect.width = tabPane.getWidth() - insets.left - insets.right;
+          tabAreaRect.height = maxTabHeight + tabAreaInsets.top
+                               + tabAreaInsets.bottom;
+          contentRect.width = tabAreaRect.width;
+          contentRect.height = tabPane.getHeight() - insets.top
+          - insets.bottom - tabAreaRect.height;
+          contentRect.x = insets.left;
+          tabAreaRect.x = insets.left;
+          if (tabPlacement == SwingConstants.BOTTOM)
+            {
+              contentRect.y = insets.top;
+              tabAreaRect.y = contentRect.y + contentRect.height;
+            }
+          else
+            {
+              tabAreaRect.y = insets.top;
+              contentRect.y = tabAreaRect.y + tabAreaRect.height;
+            }
+        }
+      else
+        {
+          int maxWidth = calculateMaxTabWidth(tabPlacement);
+
+          calcRect.height -= tabAreaInsets.top + tabAreaInsets.bottom;
+          int height = 0;
+          int runHeight = tabAreaInsets.top + insets.top;;
+          int fontHeight = fm.getHeight();
+          int left = insets.left + tabAreaInsets.left;
+          for (int i = 0; i < tabCount; i++)
+            {
+              height = calculateTabHeight(tabPlacement, i, fontHeight);
+
+              // The proper instances should exists because
+              //  assureRectsCreated() was being run already.
+              rects[i].setBounds(left, runHeight, maxWidth, height);
+              runHeight += height;
+            }
+          tabAreaRect.width = maxTabWidth + tabAreaInsets.left
+                              + tabAreaInsets.right;
+          tabAreaRect.height = tabPane.getHeight() - insets.top
+                               - insets.bottom;
+          tabAreaRect.y = insets.top;
+          contentRect.width = tabPane.getWidth() - insets.left - insets.right
+                              - tabAreaRect.width;
+          contentRect.height = tabAreaRect.height;
+          contentRect.y = insets.top;
+          if (tabPlacement == SwingConstants.LEFT)
+            {
+              tabAreaRect.x = insets.left;
+              contentRect.x = tabAreaRect.x + tabAreaRect.width;
+            }
+          else
+            {
+              contentRect.x = insets.left;
+              tabAreaRect.x = contentRect.x + contentRect.width;
+            }
+        }
+      
+      // Unlike the behavior in the WRAP_TAB_LAYOUT the selected
+      // tab is not padded specially.
+    }
+
+    /**
+     * This method is called when the JTabbedPane is laid out in
+     * SCROLL_TAB_LAYOUT. It finds the position for all components in the
+     * JTabbedPane.
+     *
+     * @param pane The JTabbedPane to be laid out.
+     */
+    public void layoutContainer(Container pane)
+    {
+      super.layoutContainer(pane);
+      int tabCount = tabPane.getTabCount();
+      Point p = null;
+      if (tabCount == 0)
+        return;
+      int tabPlacement = tabPane.getTabPlacement();
+      
+      if (tabPlacement == SwingConstants.TOP
+          || tabPlacement == SwingConstants.BOTTOM)
+        {
+          if (tabAreaRect.x + tabAreaRect.width < rects[tabCount - 1].x
+              + rects[tabCount - 1].width)
+            {
+              Dimension incrDims = incrButton.getPreferredSize();
+              Dimension decrDims = decrButton.getPreferredSize();
+
+              if (tabPlacement == SwingConstants.BOTTOM)
+                {
+                  // Align scroll buttons with the bottom border of the tabbed
+                  // pane's content area.
+                  decrButton.setBounds(tabAreaRect.x + tabAreaRect.width
+                                       - incrDims.width - decrDims.width,
+                                       tabAreaRect.y, decrDims.width,
+                                       decrDims.height);
+                  incrButton.setBounds(tabAreaRect.x + tabAreaRect.width
+                                       - incrDims.width, tabAreaRect.y,
+                                       incrDims.width, incrDims.height);
+                }
+              else
+                {
+                  // Align scroll buttons with the top border of the tabbed
+                  // pane's content area.
+                  decrButton.setBounds(tabAreaRect.x + tabAreaRect.width
+                                       - incrDims.width - decrDims.width,
+                                       tabAreaRect.y + tabAreaRect.height
+                                       - decrDims.height, decrDims.width,
+                                       decrDims.height);
+                  incrButton.setBounds(tabAreaRect.x + tabAreaRect.width
+                                       - incrDims.width,
+                                       tabAreaRect.y + tabAreaRect.height
+                                       - incrDims.height,
+                                       incrDims.width, incrDims.height);
+                }
+              
+              tabAreaRect.width -= decrDims.width + incrDims.width;
+              
+              updateButtons();
+              
+              incrButton.setVisible(true);
+              decrButton.setVisible(true);
+            }
+          else
+            {
+              incrButton.setVisible(false);
+              decrButton.setVisible(false);
+              
+              currentScrollOffset = 0;
+              currentScrollLocation = 0;
+            }
+        }
+
+      if (tabPlacement == SwingConstants.LEFT
+          || tabPlacement == SwingConstants.RIGHT)
+        {
+          if (tabAreaRect.y + tabAreaRect.height < rects[tabCount - 1].y
+              + rects[tabCount - 1].height)
+            {
+              Dimension incrDims = incrButton.getPreferredSize();
+              Dimension decrDims = decrButton.getPreferredSize();
+
+              if (tabPlacement == SwingConstants.RIGHT)
+                {
+                  // Align scroll buttons with the right border of the tabbed
+                  // pane's content area.
+                  decrButton.setBounds(tabAreaRect.x,
+                                       tabAreaRect.y + tabAreaRect.height
+                                       - incrDims.height - decrDims.height,
+                                       decrDims.width, decrDims.height);
+                  incrButton.setBounds(tabAreaRect.x,
+                                       tabAreaRect.y + tabAreaRect.height
+                                       - incrDims.height, incrDims.width,
+                                       incrDims.height);
+                }
+              else
+                {
+                  // Align scroll buttons with the left border of the tabbed
+                  // pane's content area.
+                  decrButton.setBounds(tabAreaRect.x + tabAreaRect.width
+                                       - decrDims.width,
+                                       tabAreaRect.y + tabAreaRect.height
+                                       - incrDims.height - decrDims.height,
+                                       decrDims.width, decrDims.height);
+                  incrButton.setBounds(tabAreaRect.x + tabAreaRect.width
+                                       - incrDims.width,
+                                       tabAreaRect.y + tabAreaRect.height
+                                       - incrDims.height, incrDims.width,
+                                       incrDims.height);
+                }
+
+              tabAreaRect.height -= decrDims.height + incrDims.height;
+
+              incrButton.setVisible(true);
+              decrButton.setVisible(true);
+            }
+          else
+            {
+              incrButton.setVisible(false);
+              decrButton.setVisible(false);
+
+              currentScrollOffset = 0;
+              currentScrollLocation = 0;
+            }
+        }
+      viewport.setBounds(tabAreaRect.x, tabAreaRect.y, tabAreaRect.width,
+                         tabAreaRect.height);
+      
+      updateViewPosition();
+      
+      viewport.repaint();
+    }
+  }
+
+  /**
+   * This class handles ChangeEvents from the JTabbedPane.
+   *
+   * @specnote Apparently this class was intended to be protected,
+   *           but was made public by a compiler bug and is now
+   *           public for compatibility.
+   */
+  public class TabSelectionHandler implements ChangeListener
+  {
+    /**
+     * This method is called whenever a ChangeEvent is fired from the
+     * JTabbedPane.
+     *
+     * @param e The ChangeEvent fired.
+     */
+    public void stateChanged(ChangeEvent e)
+    {
+      selectedRun = getRunForTab(tabPane.getTabCount(),
+                                 tabPane.getSelectedIndex());
+      
+      if (tabPane.getTabLayoutPolicy() == JTabbedPane.WRAP_TAB_LAYOUT)
+        tabPane.revalidate();
+      tabPane.repaint();
+    }
+  }
+
+  /**
+   * This helper class is a JPanel that fits inside the ScrollViewport. This
+   * panel's sole job is to paint the tab rectangles inside the  viewport so
+   * that it's clipped correctly.
+   */
+  private class ScrollingPanel extends JPanel
+  {
+    /**
+     * This is a private UI class for our panel.
+     */
+    private class ScrollingPanelUI extends BasicPanelUI
+    {
+      /**
+       * This method overrides the default paint method. It paints the tab
+       * rectangles for the JTabbedPane in the panel.
+       *
+       * @param g The Graphics object to paint with.
+       * @param c The JComponent to paint.
+       */
+      public void paint(Graphics g, JComponent c)
+      {
+        int placement = tabPane.getTabPlacement();
+        g.setColor(highlight);
+        if (placement == SwingUtilities.TOP
+            || placement == SwingUtilities.BOTTOM)
+          g.fillRect(currentScrollOffset, 0,
+                     tabAreaRect.width, tabAreaRect.height);
+        else
+          g.fillRect(0, currentScrollOffset,
+                     tabAreaRect.width, tabAreaRect.height);
+    
+        paintTabArea(g, placement, tabPane.getSelectedIndex());
+      }
+    }
+
+    /**
+     * This method overrides the updateUI method. It makes the default UI for
+     * this ScrollingPanel to be  a ScrollingPanelUI.
+     */
+    public void updateUI()
+    {
+      setUI((PanelUI) new ScrollingPanelUI());
+    }
+  }
+
+  /**
+   * This is a helper class that paints the panel that paints tabs. This
+   * custom JViewport is used so that the tabs painted in the panel will be
+   * clipped. This class implements UIResource so tabs are not added when
+   * this objects of this class are added to the  JTabbedPane.
+   */
+  private class ScrollingViewport extends JViewport implements UIResource
+  {
+    // TODO: Maybe remove this inner class.
+  }
+
+  /**
+   * This is a helper class that implements UIResource so it is not added as a
+   * tab when an object of this class is added to the JTabbedPane.
+   */
+  private class ScrollingButton extends BasicArrowButton implements UIResource
+  {
+    /**
+     * Creates a ScrollingButton given the direction.
+     *
+     * @param dir The direction to point in.
+     */
+    public ScrollingButton(int dir)
+    {
+      super(dir);
+    }
+  }
+
+  /** The button that increments the current scroll location.
+   * This is package-private to avoid an accessor method.  */
+  transient ScrollingButton incrButton;
+
+  /** The button that decrements the current scroll location.
+   * This is package-private to avoid an accessor method.  */
+  transient ScrollingButton decrButton;
+
+  /** The viewport used to display the tabs.
+   * This is package-private to avoid an accessor method.  */
+  transient ScrollingViewport viewport;
+
+  /** The panel inside the viewport that paints the tabs.
+   * This is package-private to avoid an accessor method.  */
+  transient ScrollingPanel panel;
+
+  /** The starting visible tab in the run in SCROLL_TAB_MODE.
+   * This is package-private to avoid an accessor method.  */
+  transient int currentScrollLocation;
+  
+  transient int currentScrollOffset;
+
+  /** A reusable rectangle. */
+  protected Rectangle calcRect;
+
+  /** An array of Rectangles keeping track of the tabs' area and position. */
+  protected Rectangle[] rects;
+
+  /** The insets around the content area. */
+  protected Insets contentBorderInsets;
+
+  /** The extra insets around the selected tab. */
+  protected Insets selectedTabPadInsets;
+
+  /** The insets around the tab area. */
+  protected Insets tabAreaInsets;
+
+  /** The insets around each and every tab. */
+  protected Insets tabInsets;
+
+  /**
+   * The outer bottom and right edge color for both the tab and content
+   * border.
+   */
+  protected Color darkShadow;
+
+  /** The color of the focus outline on the selected tab. */
+  protected Color focus;
+
+  /** FIXME: find a use for this. */
+  protected Color highlight;
+
+  /** The top and left edge color for both the tab and content border. */
+  protected Color lightHighlight;
+
+  /** The inner bottom and right edge color for the tab and content border. */
+  protected Color shadow;
+
+  /** The maximum tab height. */
+  protected int maxTabHeight;
+
+  /** The maximum tab width. */
+  protected int maxTabWidth;
+
+  /** The number of runs in the JTabbedPane. */
+  protected int runCount;
+
+  /** The index of the run that the selected index is in. */
+  protected int selectedRun;
+
+  /** The amount of space each run overlaps the previous by. */
+  protected int tabRunOverlay;
+
+  /** The gap between text and label */
+  protected int textIconGap;
+
+  /** This array keeps track of which tabs are in which run.
+   * <p>The value at index i denotes the index of the first tab in run i.</p>
+   * <p>If the value for any index (i > 0) is 0 then (i - 1) is the last
+   * run.</p>
+   */
+  protected int[] tabRuns;
+
+  /**
+   * Indicates if the layout of the tab runs is ok or not. This is package
+   * private to avoid a synthetic accessor method.
+   */
+  boolean tabRunsDirty;
+
+  /**
+   * This is the keystroke for moving down.
+   *
+   * @deprecated 1.3
+   */
+  protected KeyStroke downKey;
+
+  /**
+   * This is the keystroke for moving left.
+   *
+   * @deprecated 1.3
+   */
+  protected KeyStroke leftKey;
+
+  /**
+   * This is the keystroke for moving right.
+   *
+   * @deprecated 1.3
+   */
+  protected KeyStroke rightKey;
+
+  /**
+   * This is the keystroke for moving up.
+   *
+   * @deprecated 1.3
+   */
+  protected KeyStroke upKey;
+
+  /** The listener that listens for focus events. */
+  protected FocusListener focusListener;
+
+  /** The listener that listens for mouse events. */
+  protected MouseListener mouseListener;
+
+  /** The listener that listens for property change events. */
+  protected PropertyChangeListener propertyChangeListener;
+
+  /** The listener that listens for change events. */
+  protected ChangeListener tabChangeListener;
+
+  /** The tab pane that this UI paints. */
+  protected JTabbedPane tabPane;
+
+  /** The current layout manager for the tabPane.
+   * This is package-private to avoid an accessor method.  */
+  transient LayoutManager layoutManager;
+
+  /** The rectangle that describes the tab area's position and size.
+   * This is package-private to avoid an accessor method.  */
+  transient Rectangle tabAreaRect;
+
+  /** The rectangle that describes the content area's position and
+   * size.  This is package-private to avoid an accessor method.  */
+  transient Rectangle contentRect;
+
+  /**
+   * The index over which the mouse is currently moving.
+   */
+  private int rolloverTab;
+
+  /**
+   * Determines if tabs are painted opaque or not. This can be adjusted using
+   * the UIManager property 'TabbedPane.tabsOpaque'.
+   */
+  private boolean tabsOpaque;
+
+  /**
+   * The currently visible component.
+   */
+  private Component visibleComponent;
+  
+  private Color selectedColor;
+  
+  private Rectangle tempTextRect = new Rectangle();
+  
+  private Rectangle tempIconRect = new Rectangle();
+  
+  /**
+   * Creates a new BasicTabbedPaneUI object.
+   */
+  public BasicTabbedPaneUI()
+  {
+    super();
+    rects = new Rectangle[0];
+    tabRuns = new int[10];
+  }
+
+  /**
+   * This method creates a ScrollingButton that  points in the appropriate
+   * direction for an increasing button.
+   * This is package-private to avoid an accessor method.
+   *
+   * @return The increase ScrollingButton.
+   */
+  ScrollingButton createIncreaseButton()
+  {
+    if (incrButton == null)
+      incrButton = new ScrollingButton(SwingConstants.NORTH);
+    if (tabPane.getTabPlacement() == SwingConstants.TOP
+        || tabPane.getTabPlacement() == SwingConstants.BOTTOM)
+      incrButton.setDirection(SwingConstants.EAST);
+    else
+      incrButton.setDirection(SwingConstants.SOUTH);
+    return incrButton;
+  }
+
+  /**
+   * This method creates a ScrollingButton that points in the appropriate
+   * direction for a decreasing button.
+   * This is package-private to avoid an accessor method.
+   *
+   * @return The decrease ScrollingButton.
+   */
+  ScrollingButton createDecreaseButton()
+  {
+    if (decrButton == null)
+      decrButton = new ScrollingButton(SwingConstants.SOUTH);
+    if (tabPane.getTabPlacement() == SwingConstants.TOP
+        || tabPane.getTabPlacement() == SwingConstants.BOTTOM)
+      decrButton.setDirection(SwingConstants.WEST);
+    else
+      decrButton.setDirection(SwingConstants.NORTH);
+    return decrButton;
+  }
+
+  /**
+   * This method finds the point to set the view  position at given the index
+   * of a tab. The tab will be the first visible tab in the run.
+   * This is package-private to avoid an accessor method.
+   *
+   * @param index The index of the first visible tab.
+   *
+   * @return The position of the first visible tab.
+   */
+  Point findPointForIndex(int index)
+  {
+    int tabPlacement = tabPane.getTabPlacement();
+    int selectedIndex = tabPane.getSelectedIndex();
+    Insets insets = getSelectedTabPadInsets(tabPlacement);
+    int w = 0;
+    int h = 0;
+
+    if (tabPlacement == TOP || tabPlacement == BOTTOM)
+      {
+        if (index > 0)
+          {
+            w += rects[index - 1].x + rects[index - 1].width;
+            if (index > selectedIndex)
+              w -= insets.left + insets.right;
+          }
+      }
+
+    else
+      {
+        if (index > 0)
+          {
+            h += rects[index - 1].y + rects[index - 1].height;
+            if (index > selectedIndex)
+              h -= insets.top + insets.bottom;
+          }
+      }
+
+    Point p = new Point(w, h);
+    return p;
+  }
+  
+  /** TabbedPanes in scrolling mode should use this method to
+   * scroll properly to the tab given by the index argument.
+   * 
+   * @param index The tab to scroll to.
+   * @param placement The tab's placement.
+   */
+  final void scrollTab(int index, int placement)
+  {
+    int diff;
+    if (index >= 0 && tabPane.isEnabledAt(index))
+      {
+        // If the user clicked on the last tab and that one was
+        // only partially visible shift the scroll offset to make
+        // it completely visible.
+        switch (placement)
+          {
+            case JTabbedPane.TOP:
+            case JTabbedPane.BOTTOM:                   
+              if ((diff = rects[index].x
+                  + rects[index].width
+                  - decrButton.getX() - currentScrollOffset) > 0)
+                currentScrollOffset += diff;
+              else if ((diff = rects[index].x - currentScrollOffset) < 0)
+                {
+                  if (index == 0)
+                    currentScrollOffset = 0;
+                  else
+                    currentScrollOffset += diff;
+                }
+
+              currentScrollLocation = tabForCoordinate(tabPane,
+                                                       currentScrollOffset,
+                                                       rects[index].y);
+              break;
+            default:
+              if ((diff = rects[index].y + rects[index].height
+                  - decrButton.getY() - currentScrollOffset) > 0)
+                currentScrollOffset += diff;
+              else if ((diff = rects[index].y - currentScrollOffset) < 0)
+                {
+                  if (index == 0)
+                    currentScrollOffset = 0;
+                  else
+                    currentScrollOffset += diff;
+                }
+  
+              currentScrollLocation = tabForCoordinate(tabPane,
+                                                       rects[index].x,
+                                                       currentScrollOffset);
+          }
+    
+        updateViewPosition();
+        updateButtons();
+      }
+  }
+  
+  /** Sets the enabled state of the increase and decrease button
+   * according to the current scrolling offset and tab pane width
+   * (or height in TOP/BOTTOM placement).
+   */
+  final void updateButtons()
+  {
+    int tc = tabPane.getTabCount();
+    
+    // The increase button should be enabled as long as the
+    // right/bottom border of the last tab is under the left/top
+    // border of the decrease button.
+    switch (tabPane.getTabPlacement())
+    {
+      case JTabbedPane.BOTTOM:
+      case JTabbedPane.TOP:
+        incrButton.setEnabled(currentScrollLocation + 1 < tc
+                              && rects[tc-1].x + rects[tc-1].width
+                              - currentScrollOffset > decrButton.getX());
+        break;
+      default:
+        incrButton.setEnabled(currentScrollLocation + 1 < tc
+                              && rects[tc-1].y + rects[tc-1].height
+                              - currentScrollOffset > decrButton.getY());
+    }
+
+    // The decrease button is enabled when the tab pane is scrolled in any way.
+    decrButton.setEnabled(currentScrollOffset > 0);
+
+  }
+
+  /**
+   * Updates the position of the scrolling viewport's view
+   * according to the current scroll offset.
+   */
+  final void updateViewPosition()
+  {
+    Point p = viewport.getViewPosition();
+  
+    switch (tabPane.getTabPlacement())
+    {
+      case JTabbedPane.LEFT:
+      case JTabbedPane.RIGHT:
+        p.y = currentScrollOffset;
+        break;
+      default:
+        p.x = currentScrollOffset;
+    }
+    
+    viewport.setViewPosition(p);
+  }
+  
+  /**
+   * This method creates a new BasicTabbedPaneUI.
+   *
+   * @param c The JComponent to create a UI for.
+   *
+   * @return A new BasicTabbedPaneUI.
+   */
+  public static ComponentUI createUI(JComponent c)
+  {
+    return new BasicTabbedPaneUI();
+  }
+
+  /**
+   * This method installs the UI for the given JComponent.
+   *
+   * @param c The JComponent to install the UI for.
+   */
+  public void installUI(JComponent c)
+  {
+    super.installUI(c);
+    if (c instanceof JTabbedPane)
+      {
+        tabPane = (JTabbedPane) c;
+        
+        installComponents();
+        installDefaults();
+        installListeners();
+        installKeyboardActions();
+        
+        layoutManager = createLayoutManager();
+        tabPane.setLayout(layoutManager);
+      }
+  }
+
+  /**
+   * This method uninstalls the UI for the  given JComponent.
+   *
+   * @param c The JComponent to uninstall the UI for.
+   */
+  public void uninstallUI(JComponent c)
+  {
+    layoutManager = null;
+
+    uninstallKeyboardActions();
+    uninstallListeners();
+    uninstallDefaults();
+    uninstallComponents();
+
+    tabPane = null;
+  }
+
+  /**
+   * This method creates the appropriate layout manager for the JTabbedPane's
+   * current tab layout policy. If the tab layout policy is
+   * SCROLL_TAB_LAYOUT, then all the associated components that need to be
+   * created will be done so now.
+   *
+   * @return A layout manager given the tab layout policy.
+   */
+  protected LayoutManager createLayoutManager()
+  {
+    if (tabPane.getTabLayoutPolicy() == JTabbedPane.WRAP_TAB_LAYOUT)
+      return new TabbedPaneLayout();
+    else
+      {
+        runCount = 1;
+        tabRuns[0] = 0;
+        
+        incrButton = createIncreaseButton();
+        incrButton.addMouseListener(mouseListener);
+
+        decrButton = createDecreaseButton();
+        decrButton.addMouseListener(mouseListener);
+        decrButton.setEnabled(false);
+
+        panel = new ScrollingPanel();
+        panel.setSize(Integer.MAX_VALUE, Integer.MAX_VALUE);
+        panel.addMouseListener(mouseListener);
+        panel.addFocusListener(focusListener);
+        
+        viewport = new ScrollingViewport();
+        viewport.setBackground(Color.LIGHT_GRAY);
+        viewport.setView(panel);
+        viewport.setLayout(null);
+        
+        tabPane.add(incrButton);
+        tabPane.add(decrButton);
+        tabPane.add(viewport);
+        
+        return new TabbedPaneScrollLayout();
+      }
+  }
+
+  /**
+   * This method installs components for this JTabbedPane.
+   */
+  protected void installComponents()
+  {
+    // Nothing to be done.
+  }
+
+  /**
+   * This method uninstalls components for this JTabbedPane.
+   */
+  protected void uninstallComponents()
+  {
+    if (incrButton != null)
+      tabPane.remove(incrButton);
+    
+    if (decrButton != null)
+      tabPane.remove(decrButton);
+
+    if (viewport != null)
+      tabPane.remove(viewport);
+  }
+
+  /**
+   * This method installs defaults for the Look and Feel.
+   */
+  protected void installDefaults()
+  {
+    LookAndFeel.installColorsAndFont(tabPane, "TabbedPane.background",
+                                     "TabbedPane.foreground",
+                                     "TabbedPane.font");
+    tabPane.setOpaque(false);
+
+    lightHighlight = UIManager.getColor("TabbedPane.highlight");
+    highlight = UIManager.getColor("TabbedPane.light");
+
+    shadow = UIManager.getColor("TabbedPane.shadow");
+    darkShadow = UIManager.getColor("TabbedPane.darkShadow");
+
+    focus = UIManager.getColor("TabbedPane.focus");
+
+    textIconGap = UIManager.getInt("TabbedPane.textIconGap");
+    tabRunOverlay = UIManager.getInt("TabbedPane.tabRunOverlay");
+
+    tabInsets = UIManager.getInsets("TabbedPane.tabInsets");
+    selectedTabPadInsets
+      = UIManager.getInsets("TabbedPane.selectedTabPadInsets");
+    tabAreaInsets = UIManager.getInsets("TabbedPane.tabAreaInsets");
+    contentBorderInsets
+      = UIManager.getInsets("TabbedPane.contentBorderInsets");
+    tabsOpaque = UIManager.getBoolean("TabbedPane.tabsOpaque");
+    
+    // Although 'TabbedPane.contentAreaColor' is not defined in the defaults
+    // of BasicLookAndFeel it is used by this class.
+    selectedColor = UIManager.getColor("TabbedPane.contentAreaColor");
+    if (selectedColor == null)
+      selectedColor = UIManager.getColor("control");
+
+    calcRect = new Rectangle();
+    tabRuns = new int[10];
+    tabAreaRect = new Rectangle();
+    contentRect = new Rectangle();
+  }
+
+  /**
+   * This method uninstalls defaults for the Look and Feel.
+   */
+  protected void uninstallDefaults()
+  {
+    calcRect = null;
+    tabAreaRect = null;
+    contentRect = null;
+    tabRuns = null;
+    
+    tempIconRect = null;
+    tempTextRect = null;
+
+    contentBorderInsets = null;
+    tabAreaInsets = null;
+    selectedTabPadInsets = null;
+    tabInsets = null;
+
+    focus = null;
+    darkShadow = null;
+    shadow = null;
+    lightHighlight = null;
+    highlight = null;
+    
+    selectedColor = null;
+  }
+
+  /**
+   * This method creates and installs the listeners for this UI.
+   */
+  protected void installListeners()
+  {
+    mouseListener = createMouseListener();
+    tabChangeListener = createChangeListener();
+    propertyChangeListener = createPropertyChangeListener();
+    focusListener = createFocusListener();
+
+    tabPane.addMouseListener(mouseListener);
+    tabPane.addChangeListener(tabChangeListener);
+    tabPane.addPropertyChangeListener(propertyChangeListener);
+    tabPane.addFocusListener(focusListener);
+  }
+
+  /**
+   * This method removes and nulls the listeners for this UI.
+   */
+  protected void uninstallListeners()
+  {
+    tabPane.removeFocusListener(focusListener);
+    tabPane.removePropertyChangeListener(propertyChangeListener);
+    tabPane.removeChangeListener(tabChangeListener);
+    tabPane.removeMouseListener(mouseListener);
+    
+    if (incrButton != null)
+      incrButton.removeMouseListener(mouseListener);
+    
+    if (decrButton != null)
+      decrButton.removeMouseListener(mouseListener);
+    
+    if (panel != null)
+      {
+        panel.removeMouseListener(mouseListener);
+        panel.removeFocusListener(focusListener);
+      }
+
+    focusListener = null;
+    propertyChangeListener = null;
+    tabChangeListener = null;
+    mouseListener = null;
+  }
+
+  /**
+   * This method creates a new MouseListener.
+   *
+   * @return A new MouseListener.
+   */
+  protected MouseListener createMouseListener()
+  {
+    return new MouseHandler();
+  }
+
+  /**
+   * This method creates a new FocusListener.
+   *
+   * @return A new FocusListener.
+   */
+  protected FocusListener createFocusListener()
+  {
+    return new FocusHandler();
+  }
+
+  /**
+   * This method creates a new ChangeListener.
+   *
+   * @return A new ChangeListener.
+   */
+  protected ChangeListener createChangeListener()
+  {
+    return new TabSelectionHandler();
+  }
+
+  /**
+   * This method creates a new PropertyChangeListener.
+   *
+   * @return A new PropertyChangeListener.
+   */
+  protected PropertyChangeListener createPropertyChangeListener()
+  {
+    return new PropertyChangeHandler();
+  }
+
+  /**
+   * This method installs keyboard actions for the JTabbedPane.
+   */
+  protected void installKeyboardActions()
+  {
+    InputMap keyMap = (InputMap) UIManager.get("TabbedPane.focusInputMap");
+    SwingUtilities.replaceUIInputMap(tabPane, JComponent.WHEN_FOCUSED, keyMap);
+
+    keyMap = (InputMap) UIManager.get("TabbedPane.ancestorInputMap");
+    SwingUtilities
+      .replaceUIInputMap(tabPane,
+                         JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT,
+                         keyMap);
+    
+    ActionMap map = getActionMap();
+    SwingUtilities.replaceUIActionMap(tabPane, map);
+  }
+
+  /**
+   * This method uninstalls keyboard actions for the JTabbedPane.
+   */
+  protected void uninstallKeyboardActions()
+  {
+    SwingUtilities.replaceUIActionMap(tabPane, null);
+    SwingUtilities.replaceUIInputMap(tabPane, JComponent.WHEN_FOCUSED, null);
+    SwingUtilities
+      .replaceUIInputMap(tabPane,
+                         JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT,
+                         null);
+  }
+
+  /**
+   * This method returns the minimum size of the JTabbedPane.
+   *
+   * @param c The JComponent to find a size for.
+   *
+   * @return The minimum size.
+   */
+  public Dimension getMinimumSize(JComponent c)
+  {
+    return layoutManager.minimumLayoutSize(tabPane);
+  }
+
+  /**
+   * This method returns the maximum size of the JTabbedPane.
+   *
+   * @param c The JComponent to find a size for.
+   *
+   * @return The maximum size.
+   */
+  public Dimension getMaximumSize(JComponent c)
+  {
+    return new Dimension(Short.MAX_VALUE, Short.MAX_VALUE);
+  }
+
+  /**
+   * This method paints the JTabbedPane.
+   *
+   * @param g The Graphics object to paint with.
+   * @param c The JComponent to paint.
+   */
+  public void paint(Graphics g, JComponent c)
+  {
+    if (!tabPane.isValid())
+      tabPane.validate();
+
+    if (tabPane.getTabCount() == 0)
+      return;
+    
+    int index = tabPane.getSelectedIndex();
+    if (index < 0)
+      index = 0;
+    
+    int tabPlacement = tabPane.getTabPlacement();
+
+    // Paint the tab area only in WRAP_TAB_LAYOUT Mode from this method
+    // because it is done through the ScrollingViewport.paint() method
+    // for the SCROLL_TAB_LAYOUT mode.
+    if (tabPane.getTabLayoutPolicy() == JTabbedPane.WRAP_TAB_LAYOUT)
+      {
+        g.setColor(highlight);
+        g.fillRect(tabAreaRect.x, tabAreaRect.y,
+                   tabAreaRect.width, tabAreaRect.height);
+        paintTabArea(g, tabPlacement, index);
+      }
+    
+    paintContentBorder(g, tabPlacement, index);
+  }
+
+  /**
+   * This method paints the tab area. This includes painting the rectangles
+   * that make up the tabs.
+   *
+   * @param g The Graphics object to paint with.
+   * @param tabPlacement The JTabbedPane's tab placement.
+   * @param selectedIndex The selected index.
+   */
+  protected void paintTabArea(Graphics g, int tabPlacement, int selectedIndex)
+  {
+    // Please note: the ordering of the painting is important. 
+    // we WANT to paint the outermost run first and then work our way in.
+    
+    // The following drawing code works for both tab layouts.
+    int tabCount = tabPane.getTabCount();
+
+    for (int i = runCount - 1; i >= 0; --i)
+      {
+        int start = tabRuns[i];
+        int next;
+        if (i == runCount - 1)
+          next = tabRuns[0];
+        else
+          next = tabRuns[i + 1];
+        int end = next != 0 ? next - 1 : tabCount - 1;
+        for (int j = start; j <= end; ++j)
+          {
+            if (j != selectedIndex)
+              {
+                paintTab(g, tabPlacement, rects, j,
+                         tempIconRect, tempTextRect);
+              }
+          }
+      }
+    
+    // Paint selected tab in front of every other tab.
+    if (selectedIndex >= 0)
+      paintTab(g, tabPlacement, rects, selectedIndex,
+               tempIconRect, tempTextRect);
+  }
+
+  /**
+   * This method paints an individual tab.
+   *
+   * @param g The Graphics object to paint with.
+   * @param tabPlacement The JTabbedPane's tab placement.
+   * @param rects The array of rectangles that keep the size and position of
+   *        the tabs.
+   * @param tabIndex The tab index to paint.
+   * @param iconRect The rectangle to use for the icon.
+   * @param textRect The rectangle to use for the text.
+   */
+  protected void paintTab(Graphics g, int tabPlacement, Rectangle[] rects,
+                          int tabIndex, Rectangle iconRect, Rectangle textRect)
+  {
+    Rectangle rect = rects[tabIndex];
+    boolean isSelected = tabIndex == tabPane.getSelectedIndex();
+    // Paint background if necessary.
+    if (tabsOpaque || tabPane.isOpaque())
+      {
+        paintTabBackground(g, tabPlacement, tabIndex, rect.x, rect.y,
+                           rect.width, rect.height, isSelected);
+      }
+
+    // Paint border.
+    paintTabBorder(g, tabPlacement, tabIndex, rect.x, rect.y, rect.width,
+                   rect.height, isSelected);
+
+
+    // Layout label.
+    FontMetrics fm = getFontMetrics();
+    Icon icon = getIconForTab(tabIndex);
+    String title = tabPane.getTitleAt(tabIndex);
+    layoutLabel(tabPlacement, fm, tabIndex, title, icon, rect, iconRect,
+                textRect, isSelected);
+    // Paint the text.
+    paintText(g, tabPlacement, tabPane.getFont(), fm, tabIndex, title,
+              textRect, isSelected);
+    
+    // Paint icon if necessary.
+    paintIcon(g, tabPlacement, tabIndex, icon, iconRect, isSelected);
+    
+    // Paint focus indicator.
+    paintFocusIndicator(g, tabPlacement, rects, tabIndex, iconRect, textRect,
+                        isSelected);
+  }
+
+  /**
+   * This method lays out the tab and finds the location to paint the  icon
+   * and text.
+   *
+   * @param tabPlacement The JTabbedPane's tab placement.
+   * @param metrics The font metrics for the font to paint with.
+   * @param tabIndex The tab index to paint.
+   * @param title The string painted.
+   * @param icon The icon painted.
+   * @param tabRect The tab bounds.
+   * @param iconRect The calculated icon bounds.
+   * @param textRect The calculated text bounds.
+   * @param isSelected Whether this tab is selected.
+   */
+  protected void layoutLabel(int tabPlacement, FontMetrics metrics,
+                             int tabIndex, String title, Icon icon,
+                             Rectangle tabRect, Rectangle iconRect,
+                             Rectangle textRect, boolean isSelected)
+  {
+    SwingUtilities.layoutCompoundLabel(metrics, title, icon,
+                                       SwingConstants.CENTER,
+                                       SwingConstants.CENTER,
+                                       SwingConstants.CENTER,
+                                       SwingConstants.RIGHT, tabRect,
+                                       iconRect, textRect, textIconGap);
+
+    int shiftX = getTabLabelShiftX(tabPlacement, tabIndex, isSelected);
+    int shiftY = getTabLabelShiftY(tabPlacement, tabIndex, isSelected);
+
+    iconRect.x += shiftX;
+    iconRect.y += shiftY;
+
+    textRect.x += shiftX;
+    textRect.y += shiftY;
+  }
+
+  /**
+   * This method paints the icon.
+   *
+   * @param g The Graphics object to paint.
+   * @param tabPlacement The JTabbedPane's tab placement.
+   * @param tabIndex The tab index to paint.
+   * @param icon The icon to paint.
+   * @param iconRect The bounds of the icon.
+   * @param isSelected Whether this tab is selected.
+   */
+  protected void paintIcon(Graphics g, int tabPlacement, int tabIndex,
+                           Icon icon, Rectangle iconRect, boolean isSelected)
+  {
+    if (icon != null)
+      icon.paintIcon(tabPane, g, iconRect.x, iconRect.y);
+  }
+
+  /**
+   * This method paints the text for the given tab.
+   *
+   * @param g The Graphics object to paint with.
+   * @param tabPlacement The JTabbedPane's tab placement.
+   * @param font The font to paint with.
+   * @param metrics The fontmetrics of the given font.
+   * @param tabIndex The tab index.
+   * @param title The string to paint.
+   * @param textRect The bounds of the string.
+   * @param isSelected Whether this tab is selected.
+   */
+  protected void paintText(Graphics g, int tabPlacement, Font font,
+                           FontMetrics metrics, int tabIndex, String title,
+                           Rectangle textRect, boolean isSelected)
+  {
+    g.setFont(font);
+    View textView = getTextViewForTab(tabIndex);
+    if (textView != null)
+      {
+        textView.paint(g, textRect);
+        return;
+      }
+
+    int ascent = metrics.getAscent();
+
+    int mnemIndex = tabPane.getDisplayedMnemonicIndexAt(tabIndex);
+    if (tabPane.isEnabled() && tabPane.isEnabledAt(tabIndex))
+      {
+        Color fg = tabPane.getForegroundAt(tabIndex);
+        if (isSelected && (fg instanceof UIResource))
+          {
+            Color selectionForeground =
+              UIManager.getColor("TabbedPane.selectionForeground");
+            if (selectionForeground != null)
+              fg = selectionForeground;
+          }
+        g.setColor(fg);
+
+        if (mnemIndex != -1)
+          BasicGraphicsUtils.drawStringUnderlineCharAt(g, title, mnemIndex,
+                                                       textRect.x,
+                                                       textRect.y + ascent);
+        else
+          g.drawString(title, textRect.x, textRect.y + ascent);
+      }
+    else
+      {
+        Color bg = tabPane.getBackgroundAt(tabIndex);
+        g.setColor(bg.brighter());
+        if (mnemIndex != -1)
+          BasicGraphicsUtils.drawStringUnderlineCharAt(g, title, mnemIndex,
+                                                       textRect.x, textRect.y
+                                                       + ascent);
+        else
+          g.drawString(title, textRect.x, textRect.y + ascent);
+
+        g.setColor(bg.darker());
+        if (mnemIndex != -1)
+          BasicGraphicsUtils.drawStringUnderlineCharAt(g, title, mnemIndex,
+                                                       textRect.x + 1,
+                                                       textRect.y + 1
+                                                       + ascent);
+        else
+          g.drawString(title, textRect.x + 1, textRect.y + 1 + ascent);
+      }
+  }
+
+  /**
+   * This method returns how much the label for the tab should shift in the X
+   * direction.
+   *
+   * @param tabPlacement The JTabbedPane's tab placement.
+   * @param tabIndex The tab index being painted.
+   * @param isSelected Whether this tab is selected.
+   *
+   * @return The amount the label should shift by in the X direction.
+   */
+  protected int getTabLabelShiftX(int tabPlacement, int tabIndex,
+                                  boolean isSelected)
+  {
+    switch (tabPlacement)
+    {
+      default:
+      case SwingUtilities.TOP:
+      case SwingUtilities.BOTTOM:
+        return 1;
+      case SwingUtilities.LEFT:
+        return (isSelected) ? -1 : 1;
+      case SwingUtilities.RIGHT:
+        return (isSelected) ? 1 : -1;
+    }
+  }
+
+  /**
+   * This method returns how much the label for the tab should shift in the Y
+   * direction.
+   *
+   * @param tabPlacement The JTabbedPane's tab placement.
+   * @param tabIndex The tab index being painted.
+   * @param isSelected Whether this tab is selected.
+   *
+   * @return The amount the label should shift by in the Y direction.
+   */
+  protected int getTabLabelShiftY(int tabPlacement, int tabIndex,
+                                  boolean isSelected)
+  {
+    switch (tabPlacement)
+    {
+      default:
+      case SwingUtilities.TOP:
+        return (isSelected) ? -1 : 1;
+      case SwingUtilities.BOTTOM:
+        return (isSelected) ? 1 : -1;
+      case SwingUtilities.LEFT:
+      case SwingUtilities.RIGHT:
+        return 0;
+    }
+  }
+
+  /**
+   * This method paints the focus rectangle around the selected tab.
+   *
+   * @param g The Graphics object to paint with.
+   * @param tabPlacement The JTabbedPane's tab placement.
+   * @param rects The array of rectangles keeping track of size and position.
+   * @param tabIndex The tab index.
+   * @param iconRect The icon bounds.
+   * @param textRect The text bounds.
+   * @param isSelected Whether this tab is selected.
+   */
+  protected void paintFocusIndicator(Graphics g, int tabPlacement,
+                                     Rectangle[] rects, int tabIndex,
+                                     Rectangle iconRect, Rectangle textRect,
+                                     boolean isSelected)
+  {
+    if (tabPane.hasFocus() && isSelected)
+      {
+        Rectangle rect = rects[tabIndex];
+        // The focus rectangle.
+        int x;
+        int y;
+        int w;
+        int h;
+
+        g.setColor(focus);
+        switch (tabPlacement)
+          {
+          case LEFT:
+            x = rect.x + 3;
+            y = rect.y + 3;
+            w = rect.width - 5;
+            h = rect.height - 6;
+            break;
+          case RIGHT:
+            x = rect.x + 2;
+            y = rect.y + 3;
+            w = rect.width - 6;
+            h = rect.height - 5;
+            break;
+          case BOTTOM:
+            x = rect.x + 3;
+            y = rect.y + 2;
+            w = rect.width - 6;
+            h = rect.height - 5;
+            break;
+          case TOP:
+          default:
+            x = rect.x + 3;
+            y = rect.y + 3;
+            w = rect.width - 6;
+            h = rect.height - 5;
+          }
+        
+        BasicGraphicsUtils.drawDashedRect(g, x, y, w, h);
+      }
+  }
+
+  /**
+   * This method paints the border for an individual tab.
+   *
+   * @param g The Graphics object to paint with.
+   * @param tabPlacement The JTabbedPane's tab placement.
+   * @param tabIndex The tab index.
+   * @param x The x position of the tab.
+   * @param y The y position of the tab.
+   * @param w The width of the tab.
+   * @param h The height of the tab.
+   * @param isSelected Whether the tab is selected.
+   */
+  protected void paintTabBorder(Graphics g, int tabPlacement, int tabIndex,
+                                int x, int y, int w, int h, boolean isSelected)
+  {
+    Color saved = g.getColor();
+
+    switch (tabPlacement)
+    {
+      case SwingConstants.TOP:
+        g.setColor(shadow);
+        // Inner right line.
+        g.drawLine(x + w - 2, y + 2, x + w - 2, y + h);
+
+        g.setColor(darkShadow);
+        // Outer right line.
+        g.drawLine(x + w - 1, y + 2, x + w - 1, y + h);
+        
+        // Upper right corner.
+        g.drawLine(x + w - 2, y + 1, x + w - 1, y + 2);
+            
+        g.setColor(lightHighlight);
+        
+        // Left line.
+        g.drawLine(x, y + 3, x, y + h);
+            
+        // Upper line.
+        g.drawLine(x + 3, y, x + w - 3, y);
+            
+        // Upper left corner.
+        g.drawLine(x, y + 2, x + 2, y);
+        
+        break;
+      case SwingConstants.LEFT:
+        g.setColor(lightHighlight);
+        // Top line.
+        g.drawLine(x + 3, y, x + w - 1, y);
+        
+        // Top left border.
+        g.drawLine(x + 2, y, x, y + 2);
+        
+        // Left line.
+        g.drawLine(x, y + 3, x, y + h - 4);
+        
+        // Bottom left corner.
+        g.drawLine(x, y + h - 3, x + 1, y + h - 2);
+        
+        g.setColor(darkShadow);
+        // Outer bottom line.
+        g.drawLine(x + 2, y + h - 1, x + w - 1, y + h - 1);
+        
+        g.setColor(shadow);
+        // Inner bottom line.
+        g.drawLine(x + 2, y + h - 2,  x + w - 1, y + h - 2);
+        
+        break;
+      case SwingConstants.BOTTOM:
+        g.setColor(shadow);
+        // Inner right line.
+        g.drawLine(x + w - 2, y, x + w - 2, y + h - 2);
+
+        // Inner bottom line.
+        g.drawLine(x + 2, y + h - 1, x + w - 3, y + h - 1);
+
+        g.setColor(darkShadow);
+        // Outer right line.
+        g.drawLine(x + w - 1, y, x + w - 1, y + h - 3);
+            
+        // Bottom right corner.
+        g.drawLine(x + w - 1, y + h - 2, x + w - 3, y + h);
+            
+        // Bottom line.
+        g.drawLine(x + 2, y + h, x + w - 4, y + h);
+            
+        g.setColor(lightHighlight);
+        // Left line.
+        g.drawLine(x, y, x, y + h - 3);
+            
+        // Bottom left corner.
+        g.drawLine(x, y + h - 2, x + 1, y + h - 1);
+        break;
+      case SwingConstants.RIGHT:
+        g.setColor(lightHighlight);
+        // Top line.
+        g.drawLine(x, y, x + w - 3, y);
+        
+        g.setColor(darkShadow);
+        // Top right corner.
+        g.drawLine(x + w - 2, y + 1, x + w - 1, y + 2);
+        
+        // Outer right line.
+        g.drawLine(x + w - 1, y + 3, x + w - 1, y + h - 3);
+        
+        // Bottom right corner.
+        g.drawLine(x + w - 2, y + h - 2, x + w - 3, y + h - 1);
+        
+        // Bottom line.
+        g.drawLine(x, y + h - 1, x + w - 4, y + h - 1);
+        
+        g.setColor(shadow);
+        
+        // Inner right line.
+        g.drawLine(x + w - 2, y + 2, x + w - 2, y + h - 3);
+        
+        // Inner bottom line.
+        g.drawLine(x, y + h - 2, x + w - 3, y + h - 2);
+        
+        break;
+    }
+    
+    g.setColor(saved);
+  }
+
+  /**
+   * This method paints the background for an individual tab.
+   *
+   * @param g The Graphics object to paint with.
+   * @param tabPlacement The JTabbedPane's tab placement.
+   * @param tabIndex The tab index.
+   * @param x The x position of the tab.
+   * @param y The y position of the tab.
+   * @param w The width of the tab.
+   * @param h The height of the tab.
+   * @param isSelected Whether the tab is selected.
+   */
+  protected void paintTabBackground(Graphics g, int tabPlacement,
+                                    int tabIndex, int x, int y, int w, int h,
+                                    boolean isSelected)
+  {
+    Color saved = g.getColor();
+    
+    if (isSelected)
+      g.setColor(selectedColor);
+    else
+      {
+        Color bg = tabPane.getBackgroundAt(tabIndex);
+        if (bg == null)
+          bg = Color.LIGHT_GRAY;
+        g.setColor(bg);
+      }
+
+    switch (tabPlacement)
+      {
+        case SwingConstants.TOP:
+          g.fillRect(x + 1, y + 1, w - 1, h - 1);
+          break;
+        case SwingConstants.BOTTOM:
+          g.fillRect(x, y, w - 1, h - 1);
+          break;
+        case SwingConstants.LEFT:
+          g.fillRect(x + 1, y + 1, w - 1, h - 2);
+          break;
+        case SwingConstants.RIGHT:
+          g.fillRect(x, y + 1, w - 1, h - 2);
+          break;
+      }
+
+    g.setColor(saved);
+  }
+
+  /**
+   * This method paints the border around the content area.
+   *
+   * @param g The Graphics object to paint with.
+   * @param tabPlacement The JTabbedPane's tab placement.
+   * @param selectedIndex The index of the selected tab.
+   */
+  protected void paintContentBorder(Graphics g, int tabPlacement,
+                                    int selectedIndex)
+  {
+    int width = tabPane.getWidth();
+    int height = tabPane.getHeight();
+    Insets insets = tabPane.getInsets();
+    Insets tabAreaInsets = getTabAreaInsets(tabPlacement);
+
+    // Calculate coordinates of content area.
+    int x = insets.left;
+    int y = insets.top;
+    int w = width - insets.left - insets.right;
+    int h = height - insets.top - insets.bottom;
+
+    switch (tabPlacement)
+    {
+    case LEFT:
+      x += calculateTabAreaWidth(tabPlacement, runCount, maxTabWidth);
+      w -= x - insets.left;
+      break;
+    case RIGHT:
+      w -= calculateTabAreaWidth(tabPlacement, runCount, maxTabWidth);
+      break;
+    case BOTTOM:
+      h -= calculateTabAreaHeight(tabPlacement, runCount, maxTabHeight);
+      break;
+    case TOP:
+    default:
+      y += calculateTabAreaHeight(tabPlacement, runCount, maxTabHeight);
+      h -= y - insets.top;
+    }
+
+    // Fill background if necessary.
+    if (tabPane.isOpaque())
+      {
+        Color bg = UIManager.getColor("TabbedPane.contentAreaColor");
+        g.setColor(bg);
+        g.fillRect(x, y, w, h);
+      }
+
+    // Paint border.
+    paintContentBorderTopEdge(g, tabPlacement, selectedIndex, x, y, w, h);
+    paintContentBorderLeftEdge(g, tabPlacement, selectedIndex, x, y, w, h);
+    paintContentBorderBottomEdge(g, tabPlacement, selectedIndex, x, y, w, h);
+    paintContentBorderRightEdge(g, tabPlacement, selectedIndex, x, y, w, h);
+  }
+
+  /**
+   * This method paints the top edge of the content border.
+   *
+   * @param g The Graphics object to paint with.
+   * @param tabPlacement The JTabbedPane's tab placement.
+   * @param selectedIndex The selected tab index.
+   * @param x The x coordinate for the content area.
+   * @param y The y coordinate for the content area.
+   * @param w The width of the content area.
+   * @param h The height of the content area.
+   */
+  protected void paintContentBorderTopEdge(Graphics g, int tabPlacement,
+                                           int selectedIndex, int x, int y,
+                                           int w, int h)
+  {
+    Color saved = g.getColor();
+    g.setColor(lightHighlight);
+
+    int startgap = rects[selectedIndex].x - currentScrollOffset;
+    int endgap = rects[selectedIndex].x + rects[selectedIndex].width
+                 - currentScrollOffset;
+
+    // Paint the highlight line with a gap if the tabs are at the top
+    // and the selected tab is inside the visible area.
+    if (tabPlacement == SwingConstants.TOP && startgap >= 0)
+      {
+        g.drawLine(x, y, startgap, y);
+        g.drawLine(endgap, y, x + w - 1, y);
+        
+        g.setColor(selectedColor);
+        g.drawLine(startgap, y, endgap - 1, y);
+      }
+    else
+      g.drawLine(x, y, x + w, y);
+    
+    g.setColor(selectedColor);
+    g.drawLine(x, y + 1, x + w - 1, y + 1);
+    g.drawLine(x, y + 2, x + w - 1, y + 2);
+    
+    g.setColor(saved);
+  }
+
+  /**
+   * This method paints the left edge of the content border.
+   *
+   * @param g The Graphics object to paint with.
+   * @param tabPlacement The JTabbedPane's tab placement.
+   * @param selectedIndex The selected tab index.
+   * @param x The x coordinate for the content area.
+   * @param y The y coordinate for the content area.
+   * @param w The width of the content area.
+   * @param h The height of the content area.
+   */
+  protected void paintContentBorderLeftEdge(Graphics g, int tabPlacement,
+                                            int selectedIndex, int x, int y,
+                                            int w, int h)
+  {
+    Color saved = g.getColor();
+    g.setColor(lightHighlight);
+
+    int startgap = rects[selectedIndex].y - currentScrollOffset;
+    int endgap = rects[selectedIndex].y + rects[selectedIndex].height
+                 - currentScrollOffset;
+
+    int diff = 0;
+
+    if (tabPlacement == SwingConstants.LEFT && startgap >= 0)
+      {
+        g.drawLine(x, y, x, startgap);
+        g.drawLine(x, endgap, x, y + h - 1);
+        
+        g.setColor(selectedColor);
+        g.drawLine(x, startgap, x, endgap - 1);
+      }
+    else
+      g.drawLine(x, y, x, y + h - 1);
+    
+    g.setColor(selectedColor);
+    g.drawLine(x + 1, y + 1, x + 1, y + h - 4);
+
+    g.setColor(saved);
+  }
+
+  /**
+   * This method paints the bottom edge of the content border.
+   *
+   * @param g The Graphics object to paint with.
+   * @param tabPlacement The JTabbedPane's tab placement.
+   * @param selectedIndex The selected tab index.
+   * @param x The x coordinate for the content area.
+   * @param y The y coordinate for the content area.
+   * @param w The width of the content area.
+   * @param h The height of the content area.
+   */
+  protected void paintContentBorderBottomEdge(Graphics g, int tabPlacement,
+                                              int selectedIndex, int x, int y,
+                                              int w, int h)
+  {
+    Color saved = g.getColor();
+
+    int startgap = rects[selectedIndex].x - currentScrollOffset;
+    int endgap = rects[selectedIndex].x + rects[selectedIndex].width
+                 - currentScrollOffset;
+
+    if (tabPlacement == SwingConstants.BOTTOM && startgap >= 0)
+      {
+        g.setColor(shadow);
+        g.drawLine(x + 1, y + h - 2, startgap, y + h - 2);
+        g.drawLine(endgap, y + h - 2, x + w - 2, y + h - 2);
+
+        g.setColor(darkShadow);
+        g.drawLine(x, y + h - 1, startgap , y + h - 1);
+        g.drawLine(endgap, y + h - 1, x + w - 1, y + h - 1);
+        
+        g.setColor(selectedColor);
+        g.drawLine(startgap, y + h - 1, endgap - 1, y + h - 1);
+        g.drawLine(startgap, y + h - 2, endgap - 1, y + h - 2);
+      }
+    else
+      {
+        g.setColor(shadow);
+        g.drawLine(x + 1, y + h - 2, x + w - 1, y + h - 2);
+        g.setColor(darkShadow);
+        g.drawLine(x, y + h - 1, x + w - 1, y + h - 1);
+      }
+    
+    g.setColor(selectedColor);
+    g.drawLine(x + 1, y + h - 3, x + w - 2, y + h - 3);
+
+    g.setColor(saved);
+  }
+
+  /**
+   * This method paints the right edge of the content border.
+   *
+   * @param g The Graphics object to paint with.
+   * @param tabPlacement The JTabbedPane's tab placement.
+   * @param selectedIndex The selected tab index.
+   * @param x The x coordinate for the content area.
+   * @param y The y coordinate for the content area.
+   * @param w The width of the content area.
+   * @param h The height of the content area.
+   */
+  protected void paintContentBorderRightEdge(Graphics g, int tabPlacement,
+                                             int selectedIndex, int x, int y,
+                                             int w, int h)
+  {
+    Color saved = g.getColor();
+    int startgap = rects[selectedIndex].y - currentScrollOffset;
+    int endgap = rects[selectedIndex].y + rects[selectedIndex].height
+                 - currentScrollOffset;
+
+    int diff = 0;
+
+    if (tabPlacement == SwingConstants.RIGHT && startgap >= 0)
+      {
+        g.setColor(shadow);
+        g.drawLine(x + w - 2, y + 1, x + w - 2, startgap);
+        g.drawLine(x + w - 2, endgap, x + w - 2, y + h - 2);
+
+        g.setColor(darkShadow);
+        g.drawLine(x + w - 1, y, x + w - 1, startgap);
+        g.drawLine(x + w - 1, endgap, x + w - 1, y + h - 2);
+        
+        g.setColor(selectedColor);
+        g.drawLine(x + w - 2, startgap, x + w - 2, endgap - 1);
+        g.drawLine(x + w - 1, startgap, x + w - 1, endgap - 1);
+      }
+    else
+      {
+        g.setColor(shadow);
+        g.drawLine(x + w - 2, y + 1, x + w - 2, y + h - 2);
+        g.setColor(darkShadow);
+        g.drawLine(x + w - 1, y, x + w - 1, y + h - 2);
+      }
+    
+    g.setColor(selectedColor);
+    g.drawLine(x + w - 3, y + 1, x + w - 3, y + h - 4);
+
+    g.setColor(saved);
+  }
+
+  /**
+   * This method returns the tab bounds for the given index.
+   *
+   * @param pane The JTabbedPane.
+   * @param i The index to look for.
+   *
+   * @return The bounds of the tab with the given index.
+   */
+  public Rectangle getTabBounds(JTabbedPane pane, int i)
+  {
+    // Need to re-layout container if tab does not exist.
+    if (i >= rects.length)
+      layoutManager.layoutContainer(pane);
+    return rects[i];
+  }
+
+  /**
+   * This method returns the number of runs.
+   *
+   * @param pane The JTabbedPane.
+   *
+   * @return The number of runs.
+   */
+  public int getTabRunCount(JTabbedPane pane)
+  {
+    return runCount;
+  }
+
+  /**
+   * This method returns the tab index given a coordinate.
+   *
+   * @param pane The JTabbedPane.
+   * @param x The x coordinate.
+   * @param y The y coordinate.
+   *
+   * @return The tab index that the coordinate lands in.
+   */
+  public int tabForCoordinate(JTabbedPane pane, int x, int y)
+  {
+    // Note: This code is tab layout mode agnostic.
+    if (! tabPane.isValid())
+      tabPane.validate();
+    
+    int tabCount = tabPane.getTabCount();
+    
+    // If the user clicked outside of any tab rect the
+    // selection should not change.
+    int index = tabPane.getSelectedIndex();
+    for (int i = 0; i < tabCount; ++i)
+      {
+        if (rects[i].contains(x, y))
+          {
+            index = i;
+            break;
+          }
+      }
+
+    return index;
+  }
+
+  /**
+   * This method returns the tab bounds in the given rectangle.
+   *
+   * @param tabIndex The index to get bounds for.
+   * @param dest The rectangle to store bounds in.
+   *
+   * @return The rectangle passed in.
+   */
+  protected Rectangle getTabBounds(int tabIndex, Rectangle dest)
+  {
+    dest.setBounds(getTabBounds(tabPane, tabIndex));
+    return dest;
+  }
+
+  /**
+   * This method returns the component that is shown in  the content area.
+   *
+   * @return The component that is shown in the content area.
+   */
+  protected Component getVisibleComponent()
+  {
+    return visibleComponent;
+  }
+
+  /**
+   * This method sets the visible component.
+   *
+   * @param component The component to be set visible.
+   */
+  protected void setVisibleComponent(Component component)
+  {
+    // Make old component invisible.
+    if (visibleComponent != null && visibleComponent != component
+        && visibleComponent.getParent() == tabPane)
+      {
+        visibleComponent.setVisible(false);
+      }
+
+    // Make new component visible.
+    if (component != null && ! component.isVisible())
+      {
+        component.setVisible(true);
+      }
+    visibleComponent = component;
+  }
+
+  /**
+   * This method assures that enough rectangles are created given the
+   * tabCount. The old array is copied to the  new one.
+   *
+   * @param tabCount The number of tabs.
+   */
+  protected void assureRectsCreated(int tabCount)
+  {
+    if (rects.length < tabCount)
+      {
+        Rectangle[] old = rects;
+        rects = new Rectangle[tabCount];
+        System.arraycopy(old, 0, rects, 0, old.length);
+        for (int i = old.length; i < rects.length; i++)
+          rects[i] = new Rectangle();
+      }
+  }
+
+  /**
+   * This method expands the tabRuns array to give it more room. The old array
+   * is copied to the new one.
+   */
+  protected void expandTabRunsArray()
+  {
+    // This method adds another 10 index positions to the tabRuns array.
+    if (tabRuns == null)
+      tabRuns = new int[10];
+    else
+      {
+        int[] newRuns = new int[tabRuns.length + 10];
+        System.arraycopy(tabRuns, 0, newRuns, 0, tabRuns.length);
+        tabRuns = newRuns;
+      }
+  }
+
+  /**
+   * This method returns which run a particular tab belongs to.
+   *
+   * @param tabCount The number of tabs.
+   * @param tabIndex The tab to find.
+   *
+   * @return The tabRuns index that it belongs to.
+   */
+  protected int getRunForTab(int tabCount, int tabIndex)
+  {
+    if (runCount == 1 && tabIndex < tabCount && tabIndex >= 0)
+      return 0;
+    for (int i = 0; i < runCount; i++)
+      {
+        int first = lastTabInRun(tabCount, getPreviousTabRun(i)) + 1;
+        if (first == tabCount)
+          first = 0;
+        int last = lastTabInRun(tabCount, i);
+        if (last >= tabIndex && first <= tabIndex)
+          return i;
+      }
+    return -1;
+  }
+
+  /**
+   * This method returns the index of the last tab in  a run.
+   *
+   * @param tabCount The number of tabs.
+   * @param run The run to check.
+   *
+   * @return The last tab in the given run.
+   */
+  protected int lastTabInRun(int tabCount, int run)
+  {
+    int lastTab;
+    if (runCount == 1)
+      lastTab = tabCount - 1;
+    else
+      {
+        int nextRun;
+        if (run == runCount - 1)
+          nextRun = 0;
+        else
+          nextRun = run + 1;
+
+        if (tabRuns[nextRun] == 0)
+          lastTab = tabCount - 1;
+        else
+          lastTab = tabRuns[nextRun] - 1;
+      }
+    return lastTab;
+  }
+
+  /**
+   * This method returns the tab run overlay.
+   *
+   * @param tabPlacement The JTabbedPane's tab placement.
+   *
+   * @return The tab run overlay.
+   */
+  protected int getTabRunOverlay(int tabPlacement)
+  {
+    return tabRunOverlay;
+  }
+
+  /**
+   * This method returns the tab run indent. It is used in WRAP_TAB_LAYOUT and
+   * makes each tab run start indented by a certain amount.
+   *
+   * @param tabPlacement The JTabbedPane's tab placement.
+   * @param run The run to get indent for.
+   *
+   * @return The amount a run should be indented.
+   */
+  protected int getTabRunIndent(int tabPlacement, int run)
+  {
+    return 0;
+  }
+
+  /**
+   * This method returns whether a tab run should be padded.
+   *
+   * @param tabPlacement The JTabbedPane's tab placement.
+   * @param run The run to check.
+   *
+   * @return Whether the given run should be padded.
+   */
+  protected boolean shouldPadTabRun(int tabPlacement, int run)
+  {
+    return true;
+  }
+
+  /**
+   * This method returns whether the tab runs should be rotated.
+   *
+   * @param tabPlacement The JTabbedPane's tab placement.
+   *
+   * @return Whether runs should be rotated.
+   */
+  protected boolean shouldRotateTabRuns(int tabPlacement)
+  {
+    return true;
+  }
+
+  /**
+   * This method returns an icon for the tab. If the tab is disabled, it
+   * should return the disabledIcon. If it is enabled, then it should return
+   * the default icon.
+   *
+   * @param tabIndex The tab index to get an icon for.
+   *
+   * @return The icon for the tab index.
+   */
+  protected Icon getIconForTab(int tabIndex)
+  {
+    if (tabPane.isEnabledAt(tabIndex))
+      return tabPane.getIconAt(tabIndex);
+    else
+      return tabPane.getDisabledIconAt(tabIndex);
+  }
+
+  /**
+   * This method returns a view that can paint the text for the label.
+   *
+   * @param tabIndex The tab index to get a view for.
+   *
+   * @return The view for the tab index.
+   */
+  protected View getTextViewForTab(int tabIndex)
+  {
+    // FIXME: When the label contains HTML this should return something
+    // non-null.
+    return null;
+  }
+
+  /**
+   * This method returns the tab height, including insets, for the given index
+   * and fontheight.
+   *
+   * @param tabPlacement The JTabbedPane's tab placement.
+   * @param tabIndex The index of the tab to calculate.
+   * @param fontHeight The font height.
+   *
+   * @return This tab's height.
+   */
+  protected int calculateTabHeight(int tabPlacement, int tabIndex,
+                                   int fontHeight)
+  {
+    // FIXME: Handle HTML by using the view (see getTextViewForTab).
+
+    int height = fontHeight;
+    Icon icon = getIconForTab(tabIndex);
+    Insets tabInsets = getTabInsets(tabPlacement, tabIndex);
+    if (icon != null)
+      height = Math.max(height, icon.getIconHeight());
+    height += tabInsets.top + tabInsets.bottom + 2;
+    return height;
+  }
+
+  /**
+   * This method returns the max tab height.
+   *
+   * @param tabPlacement The JTabbedPane's tab placement.
+   *
+   * @return The maximum tab height.
+   */
+  protected int calculateMaxTabHeight(int tabPlacement)
+  {
+    maxTabHeight = 0;
+
+    FontMetrics fm = getFontMetrics();
+    int fontHeight = fm.getHeight();
+
+    for (int i = 0; i < tabPane.getTabCount(); i++)
+      maxTabHeight = Math.max(calculateTabHeight(tabPlacement, i, fontHeight),
+                              maxTabHeight);
+
+    return maxTabHeight;
+  }
+
+  /**
+   * This method calculates the tab width, including insets, for the given tab
+   * index and font metrics.
+   *
+   * @param tabPlacement The JTabbedPane's tab placement.
+   * @param tabIndex The tab index to calculate for.
+   * @param metrics The font's metrics.
+   *
+   * @return The tab width for the given index.
+   */
+  protected int calculateTabWidth(int tabPlacement, int tabIndex,
+                                  FontMetrics metrics)
+  {
+    Icon icon = getIconForTab(tabIndex);
+    Insets insets = getTabInsets(tabPlacement, tabIndex);
+
+    int width = 0;
+    if (icon != null)
+      {
+        Rectangle vr = new Rectangle();
+        Rectangle ir = new Rectangle();
+        Rectangle tr = new Rectangle();
+        layoutLabel(tabPlacement, getFontMetrics(), tabIndex,
+                    tabPane.getTitleAt(tabIndex), icon, vr, ir, tr,
+                    tabIndex == tabPane.getSelectedIndex());
+        width = tr.union(ir).width;
+      }
+    else
+      width = metrics.stringWidth(tabPane.getTitleAt(tabIndex));
+
+    width += insets.left + insets.right;
+    return width;
+  }
+
+  /**
+   * This method calculates the max tab width.
+   *
+   * @param tabPlacement The JTabbedPane's tab placement.
+   *
+   * @return The maximum tab width.
+   */
+  protected int calculateMaxTabWidth(int tabPlacement)
+  {
+    maxTabWidth = 0;
+
+    FontMetrics fm = getFontMetrics();
+
+    for (int i = 0; i < tabPane.getTabCount(); i++)
+      maxTabWidth = Math.max(calculateTabWidth(tabPlacement, i, fm),
+                             maxTabWidth);
+
+    return maxTabWidth;
+  }
+
+  /**
+   * This method calculates the tab area height, including insets, for the
+   * given amount of runs and tab height.
+   *
+   * @param tabPlacement The JTabbedPane's tab placement.
+   * @param horizRunCount The number of runs.
+   * @param maxTabHeight The max tab height.
+   *
+   * @return The tab area height.
+   */
+  protected int calculateTabAreaHeight(int tabPlacement, int horizRunCount,
+                                       int maxTabHeight)
+  {
+    Insets insets = getTabAreaInsets(tabPlacement);
+    int tabAreaHeight = horizRunCount * maxTabHeight
+                        - (horizRunCount - 1) * tabRunOverlay;
+
+    tabAreaHeight += insets.top + insets.bottom;
+
+    return tabAreaHeight;
+  }
+
+  /**
+   * This method calculates the tab area width, including insets, for the
+   * given amount of runs and tab width.
+   *
+   * @param tabPlacement The JTabbedPane's tab placement.
+   * @param vertRunCount The number of runs.
+   * @param maxTabWidth The max tab width.
+   *
+   * @return The tab area width.
+   */
+  protected int calculateTabAreaWidth(int tabPlacement, int vertRunCount,
+                                      int maxTabWidth)
+  {
+    Insets insets = getTabAreaInsets(tabPlacement);
+    int tabAreaWidth = vertRunCount * maxTabWidth
+                       - (vertRunCount - 1) * tabRunOverlay;
+
+    tabAreaWidth += insets.left + insets.right;
+
+    return tabAreaWidth;
+  }
+
+  /**
+   * This method returns the tab insets appropriately rotated.
+   *
+   * @param tabPlacement The JTabbedPane's tab placement.
+   * @param tabIndex The tab index.
+   *
+   * @return The tab insets for the given index.
+   */
+  protected Insets getTabInsets(int tabPlacement, int tabIndex)
+  {
+    return tabInsets;
+  }
+
+  /**
+   * This method returns the selected tab pad insets appropriately rotated.
+   *
+   * @param tabPlacement The JTabbedPane's tab placement.
+   *
+   * @return The selected tab pad insets.
+   */
+  protected Insets getSelectedTabPadInsets(int tabPlacement)
+  {
+    Insets target = new Insets(0, 0, 0, 0);
+    rotateInsets(selectedTabPadInsets, target, tabPlacement);
+    return target;
+  }
+
+  /**
+   * This method returns the tab area insets appropriately rotated.
+   *
+   * @param tabPlacement The JTabbedPane's tab placement.
+   *
+   * @return The tab area insets.
+   */
+  protected Insets getTabAreaInsets(int tabPlacement)
+  {
+    Insets target = new Insets(0, 0, 0, 0);
+    rotateInsets(tabAreaInsets, target, tabPlacement);
+    return target;
+  }
+
+  /**
+   * This method returns the content border insets appropriately rotated.
+   *
+   * @param tabPlacement The JTabbedPane's tab placement.
+   *
+   * @return The content border insets.
+   */
+  protected Insets getContentBorderInsets(int tabPlacement)
+  {
+    Insets target = new Insets(0, 0, 0, 0);
+    rotateInsets(contentBorderInsets, target, tabPlacement);
+    return target;
+  }
+
+  /**
+   * This method returns the fontmetrics for the font of the JTabbedPane.
+   *
+   * @return The font metrics for the JTabbedPane.
+   */
+  protected FontMetrics getFontMetrics()
+  {
+    FontMetrics fm = tabPane.getFontMetrics(tabPane.getFont());
+    return fm;
+  }
+
+  /**
+   * This method navigates from the selected tab into the given direction. As
+   * a result, a new tab will be selected (if possible).
+   *
+   * @param direction The direction to navigate in.
+   */
+  protected void navigateSelectedTab(int direction)
+  {
+    int tabPlacement = tabPane.getTabPlacement();
+    if (tabPlacement == SwingConstants.TOP
+        || tabPlacement == SwingConstants.BOTTOM)
+      {
+        if (direction == SwingConstants.WEST)
+          selectPreviousTabInRun(tabPane.getSelectedIndex());
+        else if (direction == SwingConstants.EAST)
+          selectNextTabInRun(tabPane.getSelectedIndex());
+
+        else
+          {
+            int offset = getTabRunOffset(tabPlacement, tabPane.getTabCount(),
+                                         tabPane.getSelectedIndex(),
+                                         (tabPlacement == SwingConstants.TOP)
+                                         ? direction == SwingConstants.NORTH
+                                         : direction == SwingConstants.SOUTH);
+            selectAdjacentRunTab(tabPlacement, tabPane.getSelectedIndex(),
+                                 offset);
+          }
+      }
+    if (tabPlacement == SwingConstants.LEFT
+        || tabPlacement == SwingConstants.RIGHT)
+      {
+        if (direction == SwingConstants.NORTH)
+          selectPreviousTabInRun(tabPane.getSelectedIndex());
+        else if (direction == SwingConstants.SOUTH)
+          selectNextTabInRun(tabPane.getSelectedIndex());
+        else
+          {
+            int offset = getTabRunOffset(tabPlacement, tabPane.getTabCount(),
+                                         tabPane.getSelectedIndex(),
+                                         (tabPlacement == SwingConstants.LEFT)
+                                         ? direction == SwingConstants.WEST
+                                         : direction == SwingConstants.EAST);
+            selectAdjacentRunTab(tabPlacement, tabPane.getSelectedIndex(),
+                                 offset);
+          }
+      }
+  }
+
+  /**
+   * This method selects the next tab in the run.
+   *
+   * @param current The current selected index.
+   */
+  protected void selectNextTabInRun(int current)
+  {
+    current = getNextTabIndexInRun(tabPane.getTabCount(),
+                                   current);
+    
+    if (tabPane.getTabLayoutPolicy() == JTabbedPane.SCROLL_TAB_LAYOUT)
+      scrollTab(current, tabPane.getTabPlacement());
+
+    tabPane.setSelectedIndex(current);
+  }
+
+  /**
+   * This method selects the previous tab in the run.
+   *
+   * @param current The current selected index.
+   */
+  protected void selectPreviousTabInRun(int current)
+  {
+    current = getPreviousTabIndexInRun(tabPane.getTabCount(),
+                                       current);
+    
+    if (tabPane.getTabLayoutPolicy() == JTabbedPane.SCROLL_TAB_LAYOUT)
+      scrollTab(current, tabPane.getTabPlacement());
+
+    tabPane.setSelectedIndex(current);
+  }
+
+  /**
+   * This method selects the next tab (regardless of runs).
+   *
+   * @param current The current selected index.
+   */
+  protected void selectNextTab(int current)
+  {
+    current = getNextTabIndex(current);
+
+    if (tabPane.getTabLayoutPolicy() == JTabbedPane.SCROLL_TAB_LAYOUT)
+      scrollTab(current, tabPane.getTabPlacement());
+
+    tabPane.setSelectedIndex(current);
+  }
+
+  /**
+   * This method selects the previous tab (regardless of runs).
+   *
+   * @param current The current selected index.
+   */
+  protected void selectPreviousTab(int current)
+  {
+    current = getPreviousTabIndex(current);
+    
+    if (tabPane.getTabLayoutPolicy() == JTabbedPane.SCROLL_TAB_LAYOUT)
+      scrollTab(current, tabPane.getTabPlacement());
+
+    tabPane.setSelectedIndex(current);
+  }
+
+  /**
+   * This method selects the correct tab given an offset from the current tab
+   * index. If the tab placement is TOP or BOTTOM, the offset will be in the
+   * y direction, otherwise, it will be in the x direction. A new coordinate
+   * will be found by adding the offset to the current location of the tab.
+   * The tab that the new location will be selected.
+   *
+   * @param tabPlacement The JTabbedPane's tab placement.
+   * @param tabIndex The tab to start from.
+   * @param offset The coordinate offset.
+   */
+  protected void selectAdjacentRunTab(int tabPlacement, int tabIndex,
+                                      int offset)
+  {
+    int x = rects[tabIndex].x + rects[tabIndex].width / 2;
+    int y = rects[tabIndex].y + rects[tabIndex].height / 2;
+
+    switch (tabPlacement)
+    {
+    case SwingConstants.TOP:
+    case SwingConstants.BOTTOM:
+      y += offset;
+      break;
+    case SwingConstants.RIGHT:
+    case SwingConstants.LEFT:
+      x += offset;
+      break;
+    }
+
+    int index = tabForCoordinate(tabPane, x, y);
+    if (index != -1)
+      {
+        if (tabPane.getTabLayoutPolicy() == JTabbedPane.SCROLL_TAB_LAYOUT)
+          scrollTab(index, tabPlacement);
+        tabPane.setSelectedIndex(index);
+      }
+  }
+
+  // This method is called when you press up/down to cycle through tab runs.
+  // it returns the distance (between the two runs' x/y position.
+  // where one run is the current selected run and the other run is the run in the
+  // direction of the scroll (dictated by the forward flag)
+  // the offset is an absolute value of the difference
+
+  /**
+   * This method calculates the offset distance for use in
+   * selectAdjacentRunTab. The offset returned will be a difference in the y
+   * coordinate between the run in  the desired direction and the current run
+   * (for tabPlacement in TOP or BOTTOM). Use x coordinate for LEFT and
+   * RIGHT.
+   *
+   * @param tabPlacement The JTabbedPane's tab placement.
+   * @param tabCount The number of tabs.
+   * @param tabIndex The starting index.
+   * @param forward If forward, the run in the desired direction will be the
+   *        next run.
+   *
+   * @return The offset between the two runs.
+   */
+  protected int getTabRunOffset(int tabPlacement, int tabCount, int tabIndex,
+                                boolean forward)
+  {
+    int currRun = getRunForTab(tabCount, tabIndex);
+    int offset;
+    int nextRun = forward ? getNextTabRun(currRun) : getPreviousTabRun(currRun);
+    if (tabPlacement == SwingConstants.TOP
+        || tabPlacement == SwingConstants.BOTTOM)
+      offset = rects[lastTabInRun(tabCount, nextRun)].y
+               - rects[lastTabInRun(tabCount, currRun)].y;
+    else
+      offset = rects[lastTabInRun(tabCount, nextRun)].x
+               - rects[lastTabInRun(tabCount, currRun)].x;
+
+    return offset;
+  }
+
+  /**
+   * This method returns the previous tab index.
+   *
+   * @param base The index to start from.
+   *
+   * @return The previous tab index.
+   */
+  protected int getPreviousTabIndex(int base)
+  {
+    base--;
+    if (base < 0)
+      return tabPane.getTabCount() - 1;
+    return base;
+  }
+
+  /**
+   * This method returns the next tab index.
+   *
+   * @param base The index to start from.
+   *
+   * @return The next tab index.
+   */
+  protected int getNextTabIndex(int base)
+  {
+    base++;
+    if (base == tabPane.getTabCount())
+      return 0;
+    return base;
+  }
+
+  /**
+   * This method returns the next tab index in the run. If the next index is
+   * out of this run, it will return the starting tab index for the run.
+   *
+   * @param tabCount The number of tabs.
+   * @param base The index to start from.
+   *
+   * @return The next tab index in the run.
+   */
+  protected int getNextTabIndexInRun(int tabCount, int base)
+  {
+    int index = getNextTabIndex(base);
+    int run = getRunForTab(tabCount, base);
+    if (base == lastTabInRun(tabCount, run))
+      index = (run > 0) 
+              ? lastTabInRun(tabCount, getPreviousTabRun(run)) + 1
+              : 0;
+    
+    return index;
+  }
+
+  /**
+   * This method returns the previous tab index in the run. If the previous
+   * index is out of this run, it will return the last index for the run.
+   *
+   * @param tabCount The number of tabs.
+   * @param base The index to start from.
+   *
+   * @return The previous tab index in the run.
+   */
+  protected int getPreviousTabIndexInRun(int tabCount, int base)
+  {
+    int index = getPreviousTabIndex(base);
+    int run = getRunForTab(tabCount, base);
+    if (index == lastTabInRun(tabCount, getPreviousTabRun(run)))
+      index = lastTabInRun(tabCount, run);
+    
+    return index;
+  }
+
+  /**
+   * This method returns the index of the previous run.
+   *
+   * @param baseRun The run to start from.
+   *
+   * @return The index of the previous run.
+   */
+  protected int getPreviousTabRun(int baseRun)
+  {
+    if (getTabRunCount(tabPane) == 1)
+      return 1;
+
+    int prevRun = --baseRun;
+    if (prevRun < 0)
+      prevRun = getTabRunCount(tabPane) - 1;
+    return prevRun;
+  }
+
+  /**
+   * This method returns the index of the next run.
+   *
+   * @param baseRun The run to start from.
+   *
+   * @return The index of the next run.
+   */
+  protected int getNextTabRun(int baseRun)
+  {
+    if (getTabRunCount(tabPane) == 1)
+      return 1;
+
+    int nextRun = ++baseRun;
+    if (nextRun == getTabRunCount(tabPane))
+      nextRun = 0;
+    return nextRun;
+  }
+
+  /**
+   * This method rotates the insets given a direction to rotate them in.
+   * Target placement should be one of TOP, LEFT, BOTTOM, RIGHT. The  rotated
+   * insets will be stored in targetInsets. Passing in TOP as  the direction
+   * does nothing. Passing in LEFT switches top and left, right and bottom.
+   * Passing in BOTTOM switches top and bottom. Passing in RIGHT switches top
+   * for left, left for bottom, bottom for right, and right for top.
+   *
+   * @param topInsets The reference insets.
+   * @param targetInsets An Insets object to store the new insets.
+   * @param targetPlacement The rotation direction.
+   */
+  protected static void rotateInsets(Insets topInsets, Insets targetInsets,
+                                     int targetPlacement)
+  {
+    // Sun's version will happily throw an NPE if params are null,
+    // so I won't check it either.
+    switch (targetPlacement)
+    {
+    default:
+    case SwingConstants.TOP:
+      targetInsets.top = topInsets.top;
+      targetInsets.left = topInsets.left;
+      targetInsets.right = topInsets.right;
+      targetInsets.bottom = topInsets.bottom;
+      break;
+    case SwingConstants.LEFT:
+      targetInsets.left = topInsets.top;
+      targetInsets.top = topInsets.left;
+      targetInsets.right = topInsets.bottom;
+      targetInsets.bottom = topInsets.right;
+      break;
+    case SwingConstants.BOTTOM:
+      targetInsets.top = topInsets.bottom;
+      targetInsets.bottom = topInsets.top;
+      targetInsets.left = topInsets.left;
+      targetInsets.right = topInsets.right;
+      break;
+    case SwingConstants.RIGHT:
+      targetInsets.top = topInsets.left;
+      targetInsets.left = topInsets.bottom;
+      targetInsets.bottom = topInsets.right;
+      targetInsets.right = topInsets.top;
+      break;
+    }
+  }
+  
+  ActionMap getActionMap() 
+  {
+    ActionMap map = (ActionMap) UIManager.get("TabbedPane.actionMap");
+
+    if (map == null) // first time here
+      {
+        map = createActionMap();
+        if (map != null)
+          UIManager.put("TabbedPane.actionMap", map);
+      }
+    return map;
+  }
+
+  ActionMap createActionMap()
+  {
+    ActionMap map = new ActionMapUIResource();
+    
+    map.put("navigatePageDown", new NavigatePageDownAction());
+    map.put("navigatePageUp", new NavigatePageUpAction());
+    map.put("navigateDown",
+            new NavigateAction("navigateDown", SwingConstants.SOUTH));
+    
+    map.put("navigateUp",
+            new NavigateAction("navigateUp", SwingConstants.NORTH));
+    
+    map.put("navigateLeft",
+            new NavigateAction("navigateLeft", SwingConstants.WEST));
+    
+    map.put("navigateRight",
+            new NavigateAction("navigateRight", SwingConstants.EAST));
+    
+    map.put("requestFocusForVisibleComponent",
+            new RequestFocusForVisibleComponentAction());
+    map.put("requestFocus", new RequestFocusAction());
+    
+    return map;
+  }
+
+  /**
+   * Sets the tab which should be highlighted when in rollover mode. And
+   * <code>index</code> of <code>-1</code> means that the rollover tab
+   * is deselected (i.e. the mouse is outside of the tabarea).
+   *
+   * @param index the index of the tab that is under the mouse, <code>-1</code>
+   *        for no tab
+   *
+   * @since 1.5
+   */
+  protected void setRolloverTab(int index)
+  {
+    rolloverTab = index;
+  }
+
+  /**
+   * Retunrs the index of the tab over which the mouse is currently moving,
+   * or <code>-1</code> for no tab.
+   *
+   * @return the index of the tab over which the mouse is currently moving,
+   *         or <code>-1</code> for no tab
+   *
+   * @since 1.5
+   */
+  protected int getRolloverTab()
+  {
+    return rolloverTab;
+  }
+}

Added: llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/BasicTableHeaderUI.java
URL: http://llvm.org/viewvc/llvm-project/llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/BasicTableHeaderUI.java?rev=43913&view=auto

==============================================================================
--- llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/BasicTableHeaderUI.java (added)
+++ llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/BasicTableHeaderUI.java Thu Nov  8 16:56:19 2007
@@ -0,0 +1,570 @@
+/* BasicTableHeaderUI.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., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package javax.swing.plaf.basic;
+
+import gnu.classpath.NotImplementedException;
+
+import java.awt.Component;
+import java.awt.Cursor;
+import java.awt.Dimension;
+import java.awt.Graphics;
+import java.awt.Rectangle;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.MouseEvent;
+
+import javax.swing.CellRendererPane;
+import javax.swing.JComponent;
+import javax.swing.LookAndFeel;
+import javax.swing.Timer;
+import javax.swing.UIManager;
+import javax.swing.border.Border;
+import javax.swing.event.MouseInputListener;
+import javax.swing.plaf.ComponentUI;
+import javax.swing.plaf.TableHeaderUI;
+import javax.swing.table.JTableHeader;
+import javax.swing.table.TableCellRenderer;
+import javax.swing.table.TableColumn;
+import javax.swing.table.TableColumnModel;
+
+/**
+ * Basic pluggable look and feel interface for JTableHeader.
+ */
+public class BasicTableHeaderUI extends TableHeaderUI
+{
+  /**
+   * The width of the space (in both direction) around the column boundary,
+   * where mouse cursor changes shape into "resize"
+   */
+  static int COLUMN_BOUNDARY_TOLERANCE = 3;
+  
+  public static ComponentUI createUI(JComponent h)
+  {
+    return new BasicTableHeaderUI();
+  }
+  
+  /**
+   * The table header that is using this interface.
+   */
+  protected JTableHeader header;
+  
+  /**
+   * The mouse input listener, responsible for mouse manipulations with
+   * the table header.
+   */
+  protected MouseInputListener mouseInputListener;
+  
+  /**
+   * Paint the header cell.
+   */
+  protected CellRendererPane rendererPane;
+  
+  /**
+   * The header cell border.
+   */
+  private Border cellBorder;
+
+  /**
+   * Original mouse cursor prior to resizing.
+   */
+  private Cursor originalCursor;
+  
+  /**
+   * If not null, one of the columns is currently being dragged.
+   */
+  Rectangle draggingHeaderRect;
+  
+  /**
+   * Handles column movement and rearrangement by mouse. The same instance works
+   * both as mouse listener and the mouse motion listner.
+   */
+  public class MouseInputHandler
+      implements MouseInputListener
+  {
+    /**
+     * If true, the cursor is being already shown in the alternative "resize"
+     * shape. 
+     */
+    boolean showingResizeCursor;
+
+    /**
+     * The position, from where the cursor is dragged during resizing. Double
+     * purpose field (absolute value during resizing and relative offset during
+     * column dragging).
+     */
+    int draggingFrom = - 1;
+    
+    /**
+     * The number of the column being dragged.
+     */
+    int draggingColumnNumber;    
+
+    /**
+     * The previous preferred width of the column.
+     */
+    int prevPrefWidth = - 1;
+
+    /**
+     * The timer to coalesce column resizing events.
+     */
+    Timer timer;
+
+    /**
+     * Returns without action, part of the MouseInputListener interface.
+     */
+    public void mouseClicked(MouseEvent e)
+    {
+      // Nothing to do.
+    }
+
+    /**
+     * If being in the resizing mode, handle resizing.
+     */
+    public void mouseDragged(MouseEvent e)
+    {
+      TableColumn resizeIt = header.getResizingColumn();
+      if (resizeIt != null && header.getResizingAllowed())
+        {
+          // The timer is intialised on demand.
+          if (timer == null)
+            {
+              // The purpose of timer is to coalesce events. If the queue
+              // is free, the repaint event is fired immediately.
+              timer = new Timer(1, new ActionListener()
+              {
+                public void actionPerformed(ActionEvent e)
+                {
+                  header.getTable().doLayout();
+                }
+              });
+              timer.setRepeats(false);
+              timer.setCoalesce(true);
+            }
+          resizeIt.setPreferredWidth(prevPrefWidth + e.getX() - draggingFrom);
+          timer.restart();
+        }
+      else if (draggingHeaderRect != null && header.getReorderingAllowed())
+        {
+          draggingHeaderRect.x = e.getX() + draggingFrom;
+          header.repaint();
+        }
+    }
+
+    /**
+     * Returns without action, part of the MouseInputListener interface.
+     */
+    public void mouseEntered(MouseEvent e)
+    {
+      // Nothing to do.
+    }
+
+    /**
+     * Reset drag information of the column resizing.
+     */
+    public void mouseExited(MouseEvent e)
+    {
+      // Nothing to do.
+    }
+
+    /**
+     * Change the mouse cursor if the mouse if above the column boundary.
+     */
+    public void mouseMoved(MouseEvent e)
+    {
+      // When dragging, the functionality is handled by the mouseDragged.
+      if (e.getButton() == 0 && header.getResizingAllowed())
+        {
+          TableColumnModel model = header.getColumnModel();
+          int n = model.getColumnCount();
+          if (n < 2)
+            // It must be at least two columns to have at least one boundary.
+            // Otherwise, nothing to do.
+            return;
+
+          boolean onBoundary = false;
+
+          int x = e.getX();
+          int a = x - COLUMN_BOUNDARY_TOLERANCE;
+          int b = x + COLUMN_BOUNDARY_TOLERANCE;
+
+          int p = 0;
+
+          Scan: for (int i = 0; i < n - 1; i++)
+            {
+              p += model.getColumn(i).getWidth();
+
+              if (p >= a && p <= b)
+                {
+                  TableColumn column = model.getColumn(i);
+                  onBoundary = true;
+
+                  draggingFrom = x;
+                  prevPrefWidth = column.getWidth();
+                  header.setResizingColumn(column);
+                  break Scan;
+                }
+            }
+
+          if (onBoundary != showingResizeCursor)
+            {
+              // Change the cursor shape, if needed.
+              if (onBoundary)
+                {
+
+		  originalCursor = header.getCursor();
+                  if (p < x)
+                    header.setCursor(Cursor.getPredefinedCursor(
+                        Cursor.W_RESIZE_CURSOR));
+                  else
+                    header.setCursor(Cursor.getPredefinedCursor(
+                        Cursor.E_RESIZE_CURSOR));
+                }
+              else
+                {
+                  header.setCursor(originalCursor);
+                  header.setResizingColumn(null);
+                }
+
+              showingResizeCursor = onBoundary;
+            }
+        }
+    }
+
+    /**
+     * Starts the dragging/resizing procedure.
+     */
+    public void mousePressed(MouseEvent e)
+    {
+      if (header.getResizingAllowed())
+        {
+          TableColumn resizingColumn = header.getResizingColumn();
+          if (resizingColumn != null)
+            {
+              resizingColumn.setPreferredWidth(resizingColumn.getWidth());
+              return;
+            }
+        }
+
+      if (header.getReorderingAllowed())
+        {
+          TableColumnModel model = header.getColumnModel();
+          int n = model.getColumnCount();
+          if (n < 2)
+            // It must be at least two columns to change the column location.
+            return;
+
+          boolean onBoundary = false;
+
+          int x = e.getX();
+          int p = 0;
+          int col = - 1;
+
+          Scan: for (int i = 0; i < n; i++)
+            {
+              p += model.getColumn(i).getWidth();
+              if (p > x)
+                {
+                  col = i;
+                  break Scan;
+                }
+            }
+          if (col < 0)
+            return;
+
+          TableColumn dragIt = model.getColumn(col);
+          header.setDraggedColumn(dragIt);
+
+          draggingFrom = (p - dragIt.getWidth()) - x;
+          draggingHeaderRect = new Rectangle(header.getHeaderRect(col));
+          draggingColumnNumber = col;
+        }
+    }
+
+    /**
+     * Set all column preferred width to the current width to prevend abrupt
+     * width changes during the next resize.
+     */
+    public void mouseReleased(MouseEvent e)
+    {
+      if (header.getResizingColumn() != null && header.getResizingAllowed())
+        endResizing();
+      if (header.getDraggedColumn() != null &&  header.getReorderingAllowed())
+        endDragging(e);
+    }
+
+    /**
+     * Stop resizing session.
+     */
+    void endResizing()
+    {
+      TableColumnModel model = header.getColumnModel();
+      int n = model.getColumnCount();
+      if (n > 2)
+        {
+          TableColumn c;
+          for (int i = 0; i < n; i++)
+            {
+              c = model.getColumn(i);
+              c.setPreferredWidth(c.getWidth());
+            }
+        }
+      header.setResizingColumn(null);
+      showingResizeCursor = false;
+      if (timer != null)
+        timer.stop();
+      header.setCursor(originalCursor);
+    }
+
+    /**
+     * Stop the dragging session.
+     * 
+     * @param e the "mouse release" mouse event, needed to determing the final
+     *          location for the dragged column.
+     */
+    void endDragging(MouseEvent e)
+    {
+      header.setDraggedColumn(null);
+      draggingHeaderRect = null;
+
+      TableColumnModel model = header.getColumnModel();
+
+      // Find where have we dragged the column.
+      int x = e.getX();
+      int p = 0;
+      
+      int col = model.getColumnCount() - 1;
+      int n = model.getColumnCount();
+
+      // This loop does not find the column if the mouse if out of the 
+      // right boundary of the table header. Then we make this column the
+      // rightmost column.
+      Scan: for (int i = 0; i < n; i++)
+        {
+          p += model.getColumn(i).getWidth();
+          if (p > x)
+            {
+              col = i;
+              break Scan;
+            }
+        }
+
+      header.getTable().moveColumn(draggingColumnNumber, col);
+    }
+  }
+ 
+  /**
+   * Create and return the mouse input listener.
+   * 
+   * @return the mouse listener ({@link MouseInputHandler}, if not overridden.
+   */
+  protected MouseInputListener createMouseInputListener()
+  {
+    return new MouseInputHandler();
+  }
+  
+  /**
+   * Construct a new BasicTableHeaderUI, create mouse listeners.
+   */
+  public BasicTableHeaderUI()
+  {
+    mouseInputListener = createMouseInputListener();
+  }
+
+  protected void installDefaults()
+  {
+    LookAndFeel.installColorsAndFont(header, "TableHeader.background",
+                                     "TableHeader.foreground",
+                                     "TableHeader.font");
+    cellBorder = UIManager.getBorder("TableHeader.cellBorder");
+  }
+
+  protected void installKeyboardActions()
+    throws NotImplementedException
+  {
+    // TODO: Implement this properly.
+  }
+
+  /**
+   * Add the mouse listener and the mouse motion listener to the table
+   * header. The listeners support table column resizing and rearrangement
+   * by mouse.
+   */
+  protected void installListeners()
+  {
+    header.addMouseListener(mouseInputListener);
+    header.addMouseMotionListener(mouseInputListener);
+  }
+
+  public void installUI(JComponent c)
+  {
+    header = (JTableHeader) c;
+    rendererPane = new CellRendererPane();
+    installDefaults();
+    installKeyboardActions();
+    installListeners();
+  }
+
+  protected void uninstallDefaults()
+  {
+    header.setBackground(null);
+    header.setForeground(null);
+    header.setFont(null);
+  }
+
+  protected void uninstallKeyboardActions()
+    throws NotImplementedException
+  {
+    // TODO: Implement this properly.
+  }
+  
+  /**
+   * Remove the previously installed listeners.
+   */
+  protected void uninstallListeners()
+  {
+    header.removeMouseListener(mouseInputListener);
+    header.removeMouseMotionListener(mouseInputListener);
+  }
+
+  public void uninstallUI(JComponent c)
+  {
+    uninstallListeners();
+    uninstallKeyboardActions();
+    uninstallDefaults();
+  }
+  
+  /**
+   * Repaint the table header. 
+   */
+  public void paint(Graphics gfx, JComponent c)
+  {
+    TableColumnModel cmod = header.getColumnModel();
+    int ncols = cmod.getColumnCount();
+    if (ncols == 0)
+      return;
+    
+    Rectangle clip = gfx.getClipBounds();
+    TableCellRenderer defaultRend = header.getDefaultRenderer();
+
+    for (int i = 0; i < ncols; ++i)
+      {
+        Rectangle bounds = header.getHeaderRect(i);
+        if (bounds.intersects(clip))
+          {
+            Rectangle oldClip = gfx.getClipBounds();
+            TableColumn col = cmod.getColumn(i);
+            TableCellRenderer rend = col.getHeaderRenderer();
+            if (rend == null)
+              rend = defaultRend;
+            Object val = col.getHeaderValue();
+            Component comp = rend.getTableCellRendererComponent(header.getTable(),
+                                                                val,
+                                                                false, // isSelected
+                                                                false, // isFocused
+                                                                -1, i);
+            // FIXME: The following settings should be performed in
+            // rend.getTableCellRendererComponent().
+            comp.setFont(header.getFont());
+            comp.setBackground(header.getBackground());
+            comp.setForeground(header.getForeground());
+            if (comp instanceof JComponent)
+              ((JComponent) comp).setBorder(cellBorder);
+            rendererPane.paintComponent(gfx, comp, header, bounds.x, bounds.y,
+                                        bounds.width, bounds.height);
+          }
+      }
+    
+    // This displays a running rectangle that is much simplier than the total
+    // animation, as it is seen in Sun's application.
+    // TODO animate the collumn dragging like in Sun's jre.
+    if (draggingHeaderRect != null)
+      {
+        gfx.setColor(header.getForeground()); 
+        gfx.drawRect(draggingHeaderRect.x, draggingHeaderRect.y + 2,
+            draggingHeaderRect.width - 1, draggingHeaderRect.height - 6);
+      }
+  }
+  
+  /**
+   * Get the preferred header size.
+   * 
+   * @param ignored unused
+   * 
+   * @return the preferred size of the associated header.
+   */
+  public Dimension getPreferredSize(JComponent ignored)
+  {
+    TableColumnModel cmod = header.getColumnModel();
+    TableCellRenderer defaultRend = header.getDefaultRenderer();
+    int ncols = cmod.getColumnCount();    
+    Dimension ret = new Dimension(0, 0);
+    int spacing = 0;
+
+    if (header.getTable() != null 
+        && header.getTable().getIntercellSpacing() != null)
+      spacing = header.getTable().getIntercellSpacing().width;
+    
+    for (int i = 0; i < ncols; ++i)      
+      {
+        TableColumn col = cmod.getColumn(i);
+        TableCellRenderer rend = col.getHeaderRenderer();
+        if (rend == null)
+          rend = defaultRend;
+        Object val = col.getHeaderValue();
+        Component comp = rend.getTableCellRendererComponent(header.getTable(),
+                                                            val,
+                                                            false, // isSelected
+                                                            false, // isFocused
+                                                            -1, i);
+        comp.setFont(header.getFont());
+        comp.setBackground(header.getBackground());
+        comp.setForeground(header.getForeground());
+        if (comp instanceof JComponent)
+          ((JComponent) comp).setBorder(cellBorder);
+
+        Dimension d = comp.getPreferredSize();
+        ret.width += spacing;
+        ret.height = Math.max(d.height, ret.height);        
+      }
+    ret.width = cmod.getTotalColumnWidth();
+    return ret;
+  }
+  
+  
+}

Added: llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/BasicTableUI.java
URL: http://llvm.org/viewvc/llvm-project/llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/BasicTableUI.java?rev=43913&view=auto

==============================================================================
--- llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/BasicTableUI.java (added)
+++ llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/BasicTableUI.java Thu Nov  8 16:56:19 2007
@@ -0,0 +1,1407 @@
+/* BasicTableUI.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., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package javax.swing.plaf.basic;
+
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.ComponentOrientation;
+import java.awt.Dimension;
+import java.awt.Graphics;
+import java.awt.Point;
+import java.awt.Rectangle;
+import java.awt.event.ActionEvent;
+import java.awt.event.FocusEvent;
+import java.awt.event.FocusListener;
+import java.awt.event.KeyEvent;
+import java.awt.event.KeyListener;
+import java.awt.event.MouseEvent;
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+
+import javax.swing.AbstractAction;
+import javax.swing.Action;
+import javax.swing.ActionMap;
+import javax.swing.CellRendererPane;
+import javax.swing.DefaultCellEditor;
+import javax.swing.DefaultListSelectionModel;
+import javax.swing.InputMap;
+import javax.swing.JComponent;
+import javax.swing.JTable;
+import javax.swing.ListSelectionModel;
+import javax.swing.LookAndFeel;
+import javax.swing.SwingUtilities;
+import javax.swing.TransferHandler;
+import javax.swing.UIManager;
+import javax.swing.border.Border;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.MouseInputListener;
+import javax.swing.plaf.ActionMapUIResource;
+import javax.swing.plaf.ComponentUI;
+import javax.swing.plaf.TableUI;
+import javax.swing.table.TableCellEditor;
+import javax.swing.table.TableCellRenderer;
+import javax.swing.table.TableColumn;
+import javax.swing.table.TableColumnModel;
+import javax.swing.table.TableModel;
+
+public class BasicTableUI extends TableUI
+{
+  public static ComponentUI createUI(JComponent comp) 
+  {
+    return new BasicTableUI();
+  }
+
+  protected FocusListener focusListener;  
+  protected KeyListener keyListener;   
+  protected MouseInputListener  mouseInputListener;   
+  protected CellRendererPane rendererPane;   
+  protected JTable table;
+
+  /** The normal cell border. */
+  Border cellBorder;
+
+  /** The action bound to KeyStrokes. */
+  TableAction action;
+
+  /**
+   * Listens for changes to the tables properties.
+   */
+  private PropertyChangeListener propertyChangeListener;
+
+  /**
+   * Handles key events for the JTable. Key events should be handled through
+   * the InputMap/ActionMap mechanism since JDK1.3. This class is only there
+   * for backwards compatibility.
+   * 
+   * @author Roman Kennke (kennke at aicas.com)
+   */
+  public class KeyHandler implements KeyListener
+  {
+
+    /**
+     * Receives notification that a key has been pressed and released.
+     * Activates the editing session for the focused cell by pressing the
+     * character keys.
+     *
+     * @param event the key event
+     */
+    public void keyTyped(KeyEvent event)
+    {
+      // Key events should be handled through the InputMap/ActionMap mechanism
+      // since JDK1.3. This class is only there for backwards compatibility.
+      
+      // Editor activation is a specific kind of response to ''any''
+      // character key. Hence it is handled here.
+      if (!table.isEditing() && table.isEnabled())
+        {
+          int r = table.getSelectedRow();
+          int c = table.getSelectedColumn();
+          if (table.isCellEditable(r, c))
+            table.editCellAt(r, c);
+        }
+    }
+
+    /**
+     * Receives notification that a key has been pressed.
+     *
+     * @param event the key event
+     */
+    public void keyPressed(KeyEvent event)
+    {
+      // Key events should be handled through the InputMap/ActionMap mechanism
+      // since JDK1.3. This class is only there for backwards compatibility.
+    }
+
+    /**
+     * Receives notification that a key has been released.
+     *
+     * @param event the key event
+     */
+    public void keyReleased(KeyEvent event)
+    {
+      // Key events should be handled through the InputMap/ActionMap mechanism
+      // since JDK1.3. This class is only there for backwards compatibility.
+    }
+  }
+
+  public class FocusHandler implements FocusListener
+  {
+    public void focusGained(FocusEvent e)
+    {
+      // The only thing that is affected by a focus change seems to be
+      // how the lead cell is painted. So we repaint this cell.
+      repaintLeadCell();
+    }
+
+    public void focusLost(FocusEvent e)
+    {
+      // The only thing that is affected by a focus change seems to be
+      // how the lead cell is painted. So we repaint this cell.
+      repaintLeadCell();
+    }
+
+    /**
+     * Repaints the lead cell in response to a focus change, to refresh
+     * the display of the focus indicator.
+     */
+    private void repaintLeadCell()
+    {
+      int rowCount = table.getRowCount();
+      int columnCount = table.getColumnCount();
+      int rowLead = table.getSelectionModel().getLeadSelectionIndex();
+      int columnLead = table.getColumnModel().getSelectionModel().
+                                                       getLeadSelectionIndex();
+      if (rowLead >= 0 && rowLead < rowCount && columnLead >= 0
+          && columnLead < columnCount)
+        {
+          Rectangle dirtyRect = table.getCellRect(rowLead, columnLead, false);
+          table.repaint(dirtyRect);
+        }
+    }
+  }
+
+  public class MouseInputHandler implements MouseInputListener
+  {
+    Point begin, curr;
+
+    private void updateSelection(boolean controlPressed)
+    {
+      // Update the rows
+      int lo_row = table.rowAtPoint(begin);
+      int hi_row  = table.rowAtPoint(curr);
+      ListSelectionModel rowModel = table.getSelectionModel();
+      if (lo_row != -1 && hi_row != -1)
+        {
+          if (controlPressed && rowModel.getSelectionMode() 
+              != ListSelectionModel.SINGLE_SELECTION)
+            rowModel.addSelectionInterval(lo_row, hi_row);
+          else
+            rowModel.setSelectionInterval(lo_row, hi_row);
+        }
+      
+      // Update the columns
+      int lo_col = table.columnAtPoint(begin);
+      int hi_col = table.columnAtPoint(curr);
+      ListSelectionModel colModel = table.getColumnModel().
+        getSelectionModel();
+      if (lo_col != -1 && hi_col != -1)
+        {
+          if (controlPressed && colModel.getSelectionMode() != 
+              ListSelectionModel.SINGLE_SELECTION)
+            colModel.addSelectionInterval(lo_col, hi_col);
+          else
+            colModel.setSelectionInterval(lo_col, hi_col);
+        }
+    }
+    
+    /**
+     * For the double click, start the cell editor.
+     */
+    public void mouseClicked(MouseEvent e)
+    {
+      Point p = e.getPoint();
+      int row = table.rowAtPoint(p);
+      int col = table.columnAtPoint(p);
+      if (table.isCellEditable(row, col))
+        {
+          // If the cell editor is the default editor, we request the
+          // number of the required clicks from it. Otherwise,
+          // require two clicks (double click).
+          TableCellEditor editor = table.getCellEditor(row, col);
+          if (editor instanceof DefaultCellEditor)
+            {
+              DefaultCellEditor ce = (DefaultCellEditor) editor;
+              if (e.getClickCount() < ce.getClickCountToStart())
+                return;
+            }
+          table.editCellAt(row, col);
+        }
+    }
+
+    public void mouseDragged(MouseEvent e) 
+    {
+      if (table.isEnabled())
+        {
+          curr = new Point(e.getX(), e.getY());
+          updateSelection(e.isControlDown());
+        }
+    }
+
+    public void mouseEntered(MouseEvent e)
+    {
+      // Nothing to do here.
+    }
+
+    public void mouseExited(MouseEvent e)
+    {
+      // Nothing to do here.
+    }
+
+    public void mouseMoved(MouseEvent e)
+    {
+      // Nothing to do here.
+    }
+
+    public void mousePressed(MouseEvent e) 
+    {
+      if (table.isEnabled())
+        {
+          ListSelectionModel rowModel = table.getSelectionModel();
+          ListSelectionModel colModel = table.getColumnModel().getSelectionModel();
+          int rowLead = rowModel.getLeadSelectionIndex();
+          int colLead = colModel.getLeadSelectionIndex();
+
+          begin = new Point(e.getX(), e.getY());
+          curr = new Point(e.getX(), e.getY());
+          //if control is pressed and the cell is already selected, deselect it
+          if (e.isControlDown() && table.isCellSelected(
+              table.rowAtPoint(begin), table.columnAtPoint(begin)))
+            {                                       
+              table.getSelectionModel().
+              removeSelectionInterval(table.rowAtPoint(begin), 
+                                      table.rowAtPoint(begin));
+              table.getColumnModel().getSelectionModel().
+              removeSelectionInterval(table.columnAtPoint(begin), 
+                                      table.columnAtPoint(begin));
+            }
+          else
+            updateSelection(e.isControlDown());
+
+          // If we were editing, but the moved to another cell, stop editing
+          if (rowLead != rowModel.getLeadSelectionIndex() ||
+              colLead != colModel.getLeadSelectionIndex())
+            if (table.isEditing())
+              table.editingStopped(new ChangeEvent(e));
+
+          // Must request focus explicitly.
+          table.requestFocusInWindow();
+        }
+    }
+
+    public void mouseReleased(MouseEvent e) 
+    {
+      if (table.isEnabled())
+        {
+          begin = null;
+          curr = null;
+        }
+    }
+  }
+
+  /**
+   * Listens for changes to the model property of the JTable and adjusts some
+   * settings.
+   *
+   * @author Roman Kennke (kennke at aicas.com)
+   */
+  private class PropertyChangeHandler implements PropertyChangeListener
+  {
+    /**
+     * Receives notification if one of the JTable's properties changes.
+     *
+     * @param ev the property change event
+     */
+    public void propertyChange(PropertyChangeEvent ev)
+    {
+      String propName = ev.getPropertyName();
+      if (propName.equals("model"))
+        {
+          ListSelectionModel rowSel = table.getSelectionModel();
+          rowSel.clearSelection();
+          ListSelectionModel colSel = table.getColumnModel().getSelectionModel();
+          colSel.clearSelection();
+          TableModel model = table.getModel();
+
+          // Adjust lead and anchor selection indices of the row and column
+          // selection models.
+          if (model.getRowCount() > 0)
+            {
+              rowSel.setAnchorSelectionIndex(0);
+              rowSel.setLeadSelectionIndex(0);
+            }
+          else
+            {
+              rowSel.setAnchorSelectionIndex(-1);
+              rowSel.setLeadSelectionIndex(-1);
+            }
+          if (model.getColumnCount() > 0)
+            {
+              colSel.setAnchorSelectionIndex(0);
+              colSel.setLeadSelectionIndex(0);
+            }
+          else
+            {
+              colSel.setAnchorSelectionIndex(-1);
+              colSel.setLeadSelectionIndex(-1);
+            }
+        }
+    }
+  }
+
+  protected FocusListener createFocusListener() 
+  {
+    return new FocusHandler();
+  }
+
+  protected MouseInputListener createMouseInputListener() 
+  {
+    return new MouseInputHandler();
+  }
+
+
+  /**
+   * Creates and returns a key listener for the JTable.
+   *
+   * @return a key listener for the JTable
+   */
+  protected KeyListener createKeyListener()
+  {
+    return new KeyHandler();
+  }
+
+  /**
+   * Return the maximum size of the table. The maximum height is the row 
+    * height times the number of rows. The maximum width is the sum of 
+    * the maximum widths of each column.
+    * 
+    *  @param comp the component whose maximum size is being queried,
+    *  this is ignored.
+    *  @return a Dimension object representing the maximum size of the table,
+    *  or null if the table has no elements.
+   */
+  public Dimension getMaximumSize(JComponent comp) 
+  {
+    int maxTotalColumnWidth = 0;
+    for (int i = 0; i < table.getColumnCount(); i++)
+      maxTotalColumnWidth += table.getColumnModel().getColumn(i).getMaxWidth();
+
+    return new Dimension(maxTotalColumnWidth, getHeight());
+  }
+
+  /**
+   * Return the minimum size of the table. The minimum height is the row 
+    * height times the number of rows. The minimum width is the sum of 
+    * the minimum widths of each column.
+    * 
+    *  @param comp the component whose minimum size is being queried,
+    *  this is ignored.
+    *  @return a Dimension object representing the minimum size of the table,
+    *  or null if the table has no elements.
+   */
+  public Dimension getMinimumSize(JComponent comp) 
+  {
+    int minTotalColumnWidth = 0;
+    for (int i = 0; i < table.getColumnCount(); i++)
+      minTotalColumnWidth += table.getColumnModel().getColumn(i).getMinWidth();
+
+    return new Dimension(minTotalColumnWidth, getHeight());
+  }
+
+  /**
+   * Returns the preferred size for the table of that UI.
+   *
+   * @param comp ignored, the <code>table</code> field is used instead
+   *
+   * @return the preferred size for the table of that UI
+   */
+  public Dimension getPreferredSize(JComponent comp) 
+  {
+    int prefTotalColumnWidth = 0;
+    for (int i = 0; i < table.getColumnCount(); i++)
+      {
+        TableColumn col = table.getColumnModel().getColumn(i);
+        prefTotalColumnWidth += col.getPreferredWidth();
+      }
+    return new Dimension(prefTotalColumnWidth, getHeight());
+  }
+
+  /**
+   * Returns the table height. This helper method is used by
+   * {@link #getMinimumSize(JComponent)}, {@link #getPreferredSize(JComponent)}
+   * and {@link #getMaximumSize(JComponent)} to determine the table height.
+   *
+   * @return the table height
+   */
+  private int getHeight()
+  {
+    int height = 0;
+    int rowCount = table.getRowCount(); 
+    if (rowCount > 0 && table.getColumnCount() > 0)
+      {
+        Rectangle r = table.getCellRect(rowCount - 1, 0, true);
+        height = r.y + r.height;
+      }
+    return height;
+  }
+
+  protected void installDefaults() 
+  {
+    LookAndFeel.installColorsAndFont(table, "Table.background",
+                                     "Table.foreground", "Table.font");
+    table.setGridColor(UIManager.getColor("Table.gridColor"));
+    table.setSelectionForeground(UIManager.getColor("Table.selectionForeground"));
+    table.setSelectionBackground(UIManager.getColor("Table.selectionBackground"));
+    table.setOpaque(true);
+  }
+
+  /**
+   * Installs keyboard actions on the table.
+   */
+  protected void installKeyboardActions() 
+  {
+    // Install the input map.
+    InputMap inputMap =
+      (InputMap) SharedUIDefaults.get("Table.ancestorInputMap");
+    SwingUtilities.replaceUIInputMap(table,
+                                 JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT,
+                                 inputMap);
+
+    // FIXME: The JDK uses a LazyActionMap for parentActionMap
+    SwingUtilities.replaceUIActionMap(table, getActionMap());
+
+  }
+
+  /**
+   * Fetches the action map from  the UI defaults, or create a new one
+   * if the action map hasn't been initialized.
+   *
+   * @return the action map
+   */
+  private ActionMap getActionMap()
+  {
+    ActionMap am = (ActionMap) UIManager.get("Table.actionMap");
+    if (am == null)
+      {
+        am = createDefaultActions();
+        UIManager.getLookAndFeelDefaults().put("Table.actionMap", am);
+      }
+    return am;
+  }
+
+  private ActionMap createDefaultActions()
+  {
+    ActionMapUIResource am = new ActionMapUIResource();
+    Action action = new TableAction();
+
+    am.put("cut", TransferHandler.getCutAction());
+    am.put("copy", TransferHandler.getCopyAction());
+    am.put("paste", TransferHandler.getPasteAction());
+
+    am.put("cancel", action);
+    am.put("selectAll", action);
+    am.put("clearSelection", action);
+    am.put("startEditing", action);
+
+    am.put("selectNextRow", action);
+    am.put("selectNextRowCell", action);
+    am.put("selectNextRowExtendSelection", action);
+    am.put("selectNextRowChangeLead", action);
+
+    am.put("selectPreviousRow", action);
+    am.put("selectPreviousRowCell", action);
+    am.put("selectPreviousRowExtendSelection", action);
+    am.put("selectPreviousRowChangeLead", action);
+
+    am.put("selectNextColumn", action);
+    am.put("selectNextColumnCell", action);
+    am.put("selectNextColumnExtendSelection", action);
+    am.put("selectNextColumnChangeLead", action);
+
+    am.put("selectPreviousColumn", action);
+    am.put("selectPreviousColumnCell", action);
+    am.put("selectPreviousColumnExtendSelection", action);
+    am.put("selectPreviousColumnChangeLead", action);
+
+    am.put("scrollLeftChangeSelection", action);
+    am.put("scrollLeftExtendSelection", action);
+    am.put("scrollRightChangeSelection", action);
+    am.put("scrollRightExtendSelection", action);
+
+    am.put("scrollUpChangeSelection", action);
+    am.put("scrollUpExtendSelection", action);
+    am.put("scrollDownChangeSelection", action);
+    am.put("scrolldownExtendSelection", action);
+
+    am.put("selectFirstColumn", action);
+    am.put("selectFirstColumnExtendSelection", action);
+    am.put("selectLastColumn", action);
+    am.put("selectLastColumnExtendSelection", action);
+
+    am.put("selectFirstRow", action);
+    am.put("selectFirstRowExtendSelection", action);
+    am.put("selectLastRow", action);
+    am.put("selectLastRowExtendSelection", action);
+
+    am.put("addToSelection", action);
+    am.put("toggleAndAnchor", action);
+    am.put("extendTo", action);
+    am.put("moveSelectionTo", action);
+
+    return am;
+  }
+
+  /**
+   * This class implements the actions that we want to happen
+   * when specific keys are pressed for the JTable.  The actionPerformed
+   * method is called when a key that has been registered for the JTable
+   * is received.
+   */
+  private static class TableAction
+    extends AbstractAction
+  {
+    /**
+     * What to do when this action is called.
+     *
+     * @param e the ActionEvent that caused this action.
+     */
+    public void actionPerformed(ActionEvent e)
+    {
+      JTable table = (JTable) e.getSource();
+
+      DefaultListSelectionModel rowModel 
+          = (DefaultListSelectionModel) table.getSelectionModel();
+      DefaultListSelectionModel colModel 
+          = (DefaultListSelectionModel) table.getColumnModel().getSelectionModel();
+
+      int rowLead = rowModel.getLeadSelectionIndex();
+      int rowMax = table.getModel().getRowCount() - 1;
+      
+      int colLead = colModel.getLeadSelectionIndex();
+      int colMax = table.getModel().getColumnCount() - 1;
+
+      // The command with which the action has been called is stored
+      // in this undocumented action value. This allows us to have only
+      // one Action instance to serve all keyboard input for JTable.
+      String command = (String) getValue("__command__");
+      if (command.equals("selectPreviousRowExtendSelection"))
+        {
+          rowModel.setLeadSelectionIndex(Math.max(rowLead - 1, 0));
+        }
+      else if (command.equals("selectLastColumn"))
+        {
+          colModel.setSelectionInterval(colMax, colMax);
+        }
+      else if (command.equals("startEditing"))
+        {
+          if (table.isCellEditable(rowLead, colLead))
+            table.editCellAt(rowLead, colLead);
+        }
+      else if (command.equals("selectFirstRowExtendSelection"))
+        {              
+          rowModel.setLeadSelectionIndex(0);
+        }
+      else if (command.equals("selectFirstColumn"))
+        {
+          colModel.setSelectionInterval(0, 0);
+        }
+      else if (command.equals("selectFirstColumnExtendSelection"))
+        {
+          colModel.setLeadSelectionIndex(0);
+        }      
+      else if (command.equals("selectLastRow"))
+        {
+          rowModel.setSelectionInterval(rowMax, rowMax);
+        }
+      else if (command.equals("selectNextRowExtendSelection"))
+        {
+          rowModel.setLeadSelectionIndex(Math.min(rowLead + 1, rowMax));
+        }
+      else if (command.equals("selectFirstRow"))
+        {
+          rowModel.setSelectionInterval(0, 0);
+        }
+      else if (command.equals("selectNextColumnExtendSelection"))
+        {
+          colModel.setLeadSelectionIndex(Math.min(colLead + 1, colMax));
+        }
+      else if (command.equals("selectLastColumnExtendSelection"))
+        {
+          colModel.setLeadSelectionIndex(colMax);
+        }
+      else if (command.equals("selectPreviousColumnExtendSelection"))
+        {
+          colModel.setLeadSelectionIndex(Math.max(colLead - 1, 0));
+        }
+      else if (command.equals("selectNextRow"))
+        {
+          rowModel.setSelectionInterval(Math.min(rowLead + 1, rowMax),
+                                        Math.min(rowLead + 1, rowMax));
+        }
+      else if (command.equals("scrollUpExtendSelection"))
+        {
+          int target;
+          if (rowLead == getFirstVisibleRowIndex(table))
+            target = Math.max(0, rowLead - (getLastVisibleRowIndex(table) 
+                - getFirstVisibleRowIndex(table) + 1));
+          else
+            target = getFirstVisibleRowIndex(table);
+          
+          rowModel.setLeadSelectionIndex(target);
+          colModel.setLeadSelectionIndex(colLead);
+        }
+      else if (command.equals("selectPreviousRow"))
+        {
+          rowModel.setSelectionInterval(Math.max(rowLead - 1, 0),
+                                        Math.max(rowLead - 1, 0));
+        }
+      else if (command.equals("scrollRightChangeSelection"))
+        {
+          int target;
+          if (colLead == getLastVisibleColumnIndex(table))
+            target = Math.min(colMax, colLead
+                              + (getLastVisibleColumnIndex(table)
+                              - getFirstVisibleColumnIndex(table) + 1));
+          else
+            target = getLastVisibleColumnIndex(table);
+          
+          colModel.setSelectionInterval(target, target);
+          rowModel.setSelectionInterval(rowLead, rowLead);
+        }
+      else if (command.equals("selectPreviousColumn"))
+        {
+          colModel.setSelectionInterval(Math.max(colLead - 1, 0),
+                                        Math.max(colLead - 1, 0));
+        }
+      else if (command.equals("scrollLeftChangeSelection"))
+        {
+          int target;
+          if (colLead == getFirstVisibleColumnIndex(table))
+            target = Math.max(0, colLead - (getLastVisibleColumnIndex(table) 
+                                 - getFirstVisibleColumnIndex(table) + 1));
+          else
+            target = getFirstVisibleColumnIndex(table);
+          
+          colModel.setSelectionInterval(target, target);
+          rowModel.setSelectionInterval(rowLead, rowLead);
+        }
+      else if (command.equals("clearSelection"))
+        {
+          table.clearSelection();
+        }
+      else if (command.equals("cancel"))
+        {
+          // FIXME: implement other parts of "cancel" like undo-ing last
+          // selection.  Right now it just calls editingCancelled if
+          // we're currently editing.
+          if (table.isEditing())
+            table.editingCanceled(new ChangeEvent("cancel"));
+        }
+      else if (command.equals("selectNextRowCell")
+               || command.equals("selectPreviousRowCell")
+               || command.equals("selectNextColumnCell")
+               || command.equals("selectPreviousColumnCell"))
+        {
+          // If nothing is selected, select the first cell in the table
+          if (table.getSelectedRowCount() == 0 && 
+              table.getSelectedColumnCount() == 0)
+            {
+              rowModel.setSelectionInterval(0, 0);
+              colModel.setSelectionInterval(0, 0);
+              return;
+            }
+          
+          // If the lead selection index isn't selected (ie a remove operation
+          // happened, then set the lead to the first selected cell in the
+          // table
+          if (!table.isCellSelected(rowLead, colLead))
+            {
+              rowModel.addSelectionInterval(rowModel.getMinSelectionIndex(), 
+                                            rowModel.getMinSelectionIndex());
+              colModel.addSelectionInterval(colModel.getMinSelectionIndex(), 
+                                            colModel.getMinSelectionIndex());
+              return;
+            }
+          
+          // multRowsSelected and multColsSelected tell us if multiple rows or
+          // columns are selected, respectively
+          boolean multRowsSelected, multColsSelected;
+          multRowsSelected = table.getSelectedRowCount() > 1 &&
+            table.getRowSelectionAllowed();
+          
+          multColsSelected = table.getSelectedColumnCount() > 1 &&
+            table.getColumnSelectionAllowed();
+          
+          // If there is just one selection, select the next cell, and wrap
+          // when you get to the edges of the table.
+          if (!multColsSelected && !multRowsSelected)
+            {
+              if (command.indexOf("Column") != -1) 
+                advanceSingleSelection(colModel, colMax, rowModel, rowMax, 
+                    command.equals("selectPreviousColumnCell"));
+              else
+                advanceSingleSelection(rowModel, rowMax, colModel, colMax, 
+                    command.equals("selectPreviousRowCell"));
+              return;
+            }
+          
+          
+          // rowMinSelected and rowMaxSelected are the minimum and maximum
+          // values respectively of selected cells in the row selection model
+          // Similarly for colMinSelected and colMaxSelected.
+          int rowMaxSelected = table.getRowSelectionAllowed() ? 
+            rowModel.getMaxSelectionIndex() : table.getModel().getRowCount() - 1;
+          int rowMinSelected = table.getRowSelectionAllowed() ? 
+            rowModel.getMinSelectionIndex() : 0; 
+          int colMaxSelected = table.getColumnSelectionAllowed() ? 
+            colModel.getMaxSelectionIndex() : 
+            table.getModel().getColumnCount() - 1;
+          int colMinSelected = table.getColumnSelectionAllowed() ? 
+            colModel.getMinSelectionIndex() : 0;
+          
+          // If there are multiple rows and columns selected, select the next
+          // cell and wrap at the edges of the selection.  
+          if (command.indexOf("Column") != -1) 
+            advanceMultipleSelection(table, colModel, colMinSelected,
+                                     colMaxSelected, rowModel, rowMinSelected,
+                                     rowMaxSelected,
+                                    command.equals("selectPreviousColumnCell"),
+                                    true);
+          
+          else
+            advanceMultipleSelection(table, rowModel, rowMinSelected,
+                                     rowMaxSelected, colModel, colMinSelected,
+                                     colMaxSelected,
+                                     command.equals("selectPreviousRowCell"),
+                                     false);
+        }
+      else if (command.equals("selectNextColumn"))
+        {
+          colModel.setSelectionInterval(Math.min(colLead + 1, colMax),
+                                        Math.min(colLead + 1, colMax));
+        }
+      else if (command.equals("scrollLeftExtendSelection"))
+        {
+          int target;
+          if (colLead == getFirstVisibleColumnIndex(table))
+            target = Math.max(0, colLead - (getLastVisibleColumnIndex(table) 
+                                 - getFirstVisibleColumnIndex(table) + 1));
+          else
+            target = getFirstVisibleColumnIndex(table);
+          
+          colModel.setLeadSelectionIndex(target);
+          rowModel.setLeadSelectionIndex(rowLead);
+        }
+      else if (command.equals("scrollDownChangeSelection"))
+        {
+          int target;
+          if (rowLead == getLastVisibleRowIndex(table))
+            target = Math.min(rowMax, rowLead + (getLastVisibleRowIndex(table)
+                                      - getFirstVisibleRowIndex(table) + 1));
+          else
+            target = getLastVisibleRowIndex(table);
+          
+          rowModel.setSelectionInterval(target, target);
+          colModel.setSelectionInterval(colLead, colLead);
+        }
+      else if (command.equals("scrollRightExtendSelection"))
+        {
+          int target;
+          if (colLead == getLastVisibleColumnIndex(table))
+            target = Math.min(colMax, colLead + (getLastVisibleColumnIndex(table) 
+                - getFirstVisibleColumnIndex(table) + 1));
+          else
+            target = getLastVisibleColumnIndex(table);
+          
+          colModel.setLeadSelectionIndex(target);
+          rowModel.setLeadSelectionIndex(rowLead);
+        }
+      else if (command.equals("selectAll"))
+        {
+          table.selectAll();
+        }
+      else if (command.equals("selectLastRowExtendSelection"))
+        {
+          rowModel.setLeadSelectionIndex(rowMax);
+          colModel.setLeadSelectionIndex(colLead);
+        }
+      else if (command.equals("scrollDownExtendSelection"))
+        {
+          int target;
+          if (rowLead == getLastVisibleRowIndex(table))
+            target = Math.min(rowMax, rowLead + (getLastVisibleRowIndex(table) 
+                - getFirstVisibleRowIndex(table) + 1));
+          else
+            target = getLastVisibleRowIndex(table);
+          
+          rowModel.setLeadSelectionIndex(target);
+          colModel.setLeadSelectionIndex(colLead);
+        }      
+      else if (command.equals("scrollUpChangeSelection"))
+        {
+          int target;
+          if (rowLead == getFirstVisibleRowIndex(table))
+            target = Math.max(0, rowLead - (getLastVisibleRowIndex(table) 
+                - getFirstVisibleRowIndex(table) + 1));
+          else
+            target = getFirstVisibleRowIndex(table);
+          
+          rowModel.setSelectionInterval(target, target);
+          colModel.setSelectionInterval(colLead, colLead);
+        }
+      else if (command.equals("selectNextRowChangeLead"))
+          {
+            if (rowModel.getSelectionMode() 
+                != ListSelectionModel.MULTIPLE_INTERVAL_SELECTION)
+              {
+                // just "selectNextRow"
+                rowModel.setSelectionInterval(Math.min(rowLead + 1, rowMax),
+                                              Math.min(rowLead + 1, rowMax));
+                colModel.setSelectionInterval(colLead, colLead);
+              }
+            else
+              rowModel.moveLeadSelectionIndex(Math.min(rowLead + 1, rowMax));
+          }
+      else if (command.equals("selectPreviousRowChangeLead"))
+        {
+          if (rowModel.getSelectionMode() 
+              != ListSelectionModel.MULTIPLE_INTERVAL_SELECTION)
+            {
+              // just selectPreviousRow
+              rowModel.setSelectionInterval(Math.max(rowLead - 1, 0),
+                                            Math.min(rowLead - 1, 0));
+              colModel.setSelectionInterval(colLead, colLead);
+            }
+          else
+            rowModel.moveLeadSelectionIndex(Math.max(rowLead - 1, 0));
+        }
+      else if (command.equals("selectNextColumnChangeLead"))
+        {
+          if (colModel.getSelectionMode() 
+              != ListSelectionModel.MULTIPLE_INTERVAL_SELECTION)            
+            {
+              // just selectNextColumn
+              rowModel.setSelectionInterval(rowLead, rowLead);
+              colModel.setSelectionInterval(Math.min(colLead + 1, colMax),
+                                            Math.min(colLead + 1, colMax));
+            }
+          else
+            colModel.moveLeadSelectionIndex(Math.min(colLead + 1, colMax));
+        }
+      else if (command.equals("selectPreviousColumnChangeLead"))
+        {
+          if (colModel.getSelectionMode() 
+              != ListSelectionModel.MULTIPLE_INTERVAL_SELECTION)            
+            {
+              // just selectPreviousColumn
+              rowModel.setSelectionInterval(rowLead, rowLead);
+              colModel.setSelectionInterval(Math.max(colLead - 1, 0),
+                                            Math.max(colLead - 1, 0));
+              
+            }
+          else
+            colModel.moveLeadSelectionIndex(Math.max(colLead - 1, 0));
+        }
+      else if (command.equals("addToSelection"))
+          {
+            if (!table.isEditing())
+              {
+                int oldRowAnchor = rowModel.getAnchorSelectionIndex();
+                int oldColAnchor = colModel.getAnchorSelectionIndex();
+                rowModel.addSelectionInterval(rowLead, rowLead);
+                colModel.addSelectionInterval(colLead, colLead);
+                rowModel.setAnchorSelectionIndex(oldRowAnchor);
+                colModel.setAnchorSelectionIndex(oldColAnchor);
+              }
+          }
+      else if (command.equals("extendTo"))
+        {
+          rowModel.setSelectionInterval(rowModel.getAnchorSelectionIndex(),
+                                        rowLead);
+          colModel.setSelectionInterval(colModel.getAnchorSelectionIndex(),
+                                        colLead);
+        }
+      else if (command.equals("toggleAndAnchor"))
+        {
+          if (rowModel.isSelectedIndex(rowLead))
+            rowModel.removeSelectionInterval(rowLead, rowLead);
+          else
+            rowModel.addSelectionInterval(rowLead, rowLead);
+          
+          if (colModel.isSelectedIndex(colLead))
+            colModel.removeSelectionInterval(colLead, colLead);
+          else
+            colModel.addSelectionInterval(colLead, colLead);
+          
+          rowModel.setAnchorSelectionIndex(rowLead);
+          colModel.setAnchorSelectionIndex(colLead);
+        }
+      else if (command.equals("stopEditing"))
+        {
+          table.editingStopped(new ChangeEvent(command));
+        }
+      else 
+        {
+          // If we're here that means we bound this TableAction class
+          // to a keyboard input but we either want to ignore that input
+          // or we just haven't implemented its action yet.
+          
+          // Uncomment the following line to print the names of unused bindings
+          // when their keys are pressed
+          
+          // System.out.println ("not implemented: "+e.getActionCommand());
+        }
+
+      // Any commands whose keyStrokes should be used by the Editor should not
+      // cause editing to be stopped: ie, the SPACE sends "addToSelection" but 
+      // if the table is in editing mode, the space should not cause us to stop
+      // editing because it should be used by the Editor.
+      if (table.isEditing() && command != "startEditing"
+          && command != "addToSelection")
+        table.editingStopped(new ChangeEvent("update"));
+            
+      table.scrollRectToVisible(table.getCellRect(
+          rowModel.getLeadSelectionIndex(), colModel.getLeadSelectionIndex(), 
+          false));
+    }
+    
+    /**
+     * Returns the column index of the first visible column.
+     * @return the column index of the first visible column.
+     */
+    int getFirstVisibleColumnIndex(JTable table)
+    {
+      ComponentOrientation or = table.getComponentOrientation();
+      Rectangle r = table.getVisibleRect();
+      if (!or.isLeftToRight())
+        r.translate((int) r.getWidth() - 1, 0);
+      return table.columnAtPoint(r.getLocation());
+    }
+    
+    /**
+     * Returns the column index of the last visible column.
+     *
+     */
+    int getLastVisibleColumnIndex(JTable table)
+    {
+      ComponentOrientation or = table.getComponentOrientation();
+      Rectangle r = table.getVisibleRect();
+      if (or.isLeftToRight())
+        r.translate((int) r.getWidth() - 1, 0);
+      return table.columnAtPoint(r.getLocation());      
+    }
+    
+    /**
+     * Returns the row index of the first visible row.
+     *
+     */
+    int getFirstVisibleRowIndex(JTable table)
+    {
+      ComponentOrientation or = table.getComponentOrientation();
+      Rectangle r = table.getVisibleRect();
+      if (!or.isLeftToRight())
+        r.translate((int) r.getWidth() - 1, 0);
+      return table.rowAtPoint(r.getLocation());
+    }
+    
+    /**
+     * Returns the row index of the last visible row.
+     *
+     */
+    int getLastVisibleRowIndex(JTable table)
+    {
+      ComponentOrientation or = table.getComponentOrientation();
+      Rectangle r = table.getVisibleRect();
+      r.translate(0, (int) r.getHeight() - 1);
+      if (or.isLeftToRight())
+        r.translate((int) r.getWidth() - 1, 0);
+      // The next if makes sure that we don't return -1 simply because
+      // there is white space at the bottom of the table (ie, the display
+      // area is larger than the table)
+      if (table.rowAtPoint(r.getLocation()) == -1)
+        {
+          if (getFirstVisibleRowIndex(table) == -1)
+            return -1;
+          else
+            return table.getModel().getRowCount() - 1;
+        }
+      return table.rowAtPoint(r.getLocation());
+    }
+
+    /**
+     * A helper method for the key bindings.  Used because the actions
+     * for TAB, SHIFT-TAB, ENTER, and SHIFT-ENTER are very similar.
+     *
+     * Selects the next (previous if SHIFT pressed) column for TAB, or row for
+     * ENTER from within the currently selected cells.
+     *
+     * @param firstModel the ListSelectionModel for columns (TAB) or
+     * rows (ENTER)
+     * @param firstMin the first selected index in firstModel
+     * @param firstMax the last selected index in firstModel
+     * @param secondModel the ListSelectionModel for rows (TAB) or 
+     * columns (ENTER)
+     * @param secondMin the first selected index in secondModel
+     * @param secondMax the last selected index in secondModel
+     * @param reverse true if shift was held for the event
+     * @param eventIsTab true if TAB was pressed, false if ENTER pressed
+     */
+    void advanceMultipleSelection(JTable table, ListSelectionModel firstModel,
+                                  int firstMin,
+                                  int firstMax, ListSelectionModel secondModel, 
+                                  int secondMin, int secondMax, boolean reverse,
+                                  boolean eventIsTab)
+    {
+      // If eventIsTab, all the "firsts" correspond to columns, otherwise, to 
+      // rows "seconds" correspond to the opposite
+      int firstLead = firstModel.getLeadSelectionIndex();
+      int secondLead = secondModel.getLeadSelectionIndex();
+      int numFirsts = eventIsTab ? 
+        table.getModel().getColumnCount() : table.getModel().getRowCount();
+      int numSeconds = eventIsTab ? 
+        table.getModel().getRowCount() : table.getModel().getColumnCount();
+
+      // check if we have to wrap the "firsts" around, going to the other side
+      if ((firstLead == firstMax && !reverse) || 
+          (reverse && firstLead == firstMin))
+        {
+          firstModel.addSelectionInterval(reverse ? firstMax : firstMin, 
+                                          reverse ? firstMax : firstMin);
+          
+          // check if we have to wrap the "seconds"
+          if ((secondLead == secondMax && !reverse) || 
+              (reverse && secondLead == secondMin))
+            secondModel.addSelectionInterval(reverse ? secondMax : secondMin, 
+                                             reverse ? secondMax : secondMin);
+
+          // if we're not wrapping the seconds, we have to find out where we
+          // are within the secondModel and advance to the next cell (or 
+          // go back to the previous cell if reverse == true)
+          else
+            {
+              int[] secondsSelected;
+              if (eventIsTab && table.getRowSelectionAllowed() || 
+                  !eventIsTab && table.getColumnSelectionAllowed())
+                secondsSelected = eventIsTab ? 
+                  table.getSelectedRows() : table.getSelectedColumns();
+              else
+                {
+                  // if row selection is not allowed, then the entire column gets
+                  // selected when you click on it, so consider ALL rows selected
+                  secondsSelected = new int[numSeconds];
+                  for (int i = 0; i < numSeconds; i++)
+                  secondsSelected[i] = i;
+                }
+
+              // and now find the "next" index within the model
+              int secondIndex = reverse ? secondsSelected.length - 1 : 0;
+              if (!reverse)
+                while (secondsSelected[secondIndex] <= secondLead)
+                  secondIndex++;
+              else
+                while (secondsSelected[secondIndex] >= secondLead)
+                  secondIndex--;
+              
+              // and select it - updating the lead selection index
+              secondModel.addSelectionInterval(secondsSelected[secondIndex], 
+                                               secondsSelected[secondIndex]);
+            }
+        }
+      // We didn't have to wrap the firsts, so just find the "next" first
+      // and select it, we don't have to change "seconds"
+      else
+        {
+          int[] firstsSelected;
+          if (eventIsTab && table.getColumnSelectionAllowed() || 
+              !eventIsTab && table.getRowSelectionAllowed())
+            firstsSelected = eventIsTab ? 
+              table.getSelectedColumns() : table.getSelectedRows();
+          else
+            {
+              // if selection not allowed, consider ALL firsts to be selected
+              firstsSelected = new int[numFirsts];
+              for (int i = 0; i < numFirsts; i++)
+                firstsSelected[i] = i;
+            }
+          int firstIndex = reverse ? firstsSelected.length - 1 : 0;
+          if (!reverse)
+            while (firstsSelected[firstIndex] <= firstLead)
+              firstIndex++;
+          else 
+            while (firstsSelected[firstIndex] >= firstLead)
+              firstIndex--;
+          firstModel.addSelectionInterval(firstsSelected[firstIndex], 
+                                          firstsSelected[firstIndex]);
+          secondModel.addSelectionInterval(secondLead, secondLead);
+        }
+    }
+    
+    /** 
+     * A helper method for the key  bindings. Used because the actions
+     * for TAB, SHIFT-TAB, ENTER, and SHIFT-ENTER are very similar.
+     *
+     * Selects the next (previous if SHIFT pressed) column (TAB) or row (ENTER)
+     * in the table, changing the current selection.  All cells in the table
+     * are eligible, not just the ones that are currently selected.
+     * @param firstModel the ListSelectionModel for columns (TAB) or rows
+     * (ENTER)
+     * @param firstMax the last index in firstModel
+     * @param secondModel the ListSelectionModel for rows (TAB) or columns
+     * (ENTER)
+     * @param secondMax the last index in secondModel
+     * @param reverse true if SHIFT was pressed for the event
+     */
+
+    void advanceSingleSelection(ListSelectionModel firstModel, int firstMax, 
+                                ListSelectionModel secondModel, int secondMax, 
+                                boolean reverse)
+    {
+      // for TABs, "first" corresponds to columns and "seconds" to rows.
+      // the opposite is true for ENTERs
+      int firstLead = firstModel.getLeadSelectionIndex();
+      int secondLead = secondModel.getLeadSelectionIndex();
+      
+      // if we are going backwards subtract 2 because we later add 1
+      // for a net change of -1
+      if (reverse && (firstLead == 0))
+        {
+          // check if we have to wrap around
+          if (secondLead == 0)
+            secondLead += secondMax + 1;
+          secondLead -= 2;
+        }
+      
+      // do we have to wrap the "seconds"?
+      if (reverse && (firstLead == 0) || !reverse && (firstLead == firstMax))
+        secondModel.setSelectionInterval((secondLead + 1) % (secondMax + 1), 
+                                         (secondLead + 1) % (secondMax + 1));
+      // if not, just reselect the current lead
+      else
+        secondModel.setSelectionInterval(secondLead, secondLead);
+      
+      // if we are going backwards, subtract 2  because we add 1 later
+      // for net change of -1
+      if (reverse)
+        {
+          // check for wraparound
+          if (firstLead == 0)
+            firstLead += firstMax + 1;
+          firstLead -= 2;
+        }
+      // select the next "first"
+      firstModel.setSelectionInterval((firstLead + 1) % (firstMax + 1), 
+                                      (firstLead + 1) % (firstMax + 1));
+    }
+  }
+
+  protected void installListeners() 
+  {
+    if (focusListener == null)
+      focusListener = createFocusListener();
+    table.addFocusListener(focusListener);
+    if (keyListener == null)
+      keyListener = createKeyListener();
+    table.addKeyListener(keyListener);
+    if (mouseInputListener == null)
+      mouseInputListener = createMouseInputListener();
+    table.addMouseListener(mouseInputListener);    
+    table.addMouseMotionListener(mouseInputListener);
+    if (propertyChangeListener == null)
+      propertyChangeListener = new PropertyChangeHandler();
+    table.addPropertyChangeListener(propertyChangeListener);
+  }
+
+  /**
+   * Uninstalls UI defaults that have been installed by
+   * {@link #installDefaults()}.
+   */
+  protected void uninstallDefaults()
+  {
+    // Nothing to do here for now.
+  }
+
+  /**
+   * Uninstalls the keyboard actions that have been installed by
+   * {@link #installKeyboardActions()}.
+   */
+  protected void uninstallKeyboardActions()
+  {
+    SwingUtilities.replaceUIInputMap(table, JComponent.
+                                     WHEN_ANCESTOR_OF_FOCUSED_COMPONENT, null);
+    SwingUtilities.replaceUIActionMap(table, null);
+  }
+
+  protected void uninstallListeners() 
+  {
+    table.removeFocusListener(focusListener);  
+    table.removeKeyListener(keyListener);
+    table.removeMouseListener(mouseInputListener);    
+    table.removeMouseMotionListener(mouseInputListener);
+    table.removePropertyChangeListener(propertyChangeListener);
+    propertyChangeListener = null;
+  }
+
+  public void installUI(JComponent comp) 
+  {
+    table = (JTable) comp;
+    rendererPane = new CellRendererPane();
+    table.add(rendererPane);
+
+    installDefaults();
+    installKeyboardActions();
+    installListeners();
+  }
+
+  public void uninstallUI(JComponent c) 
+  {
+    uninstallListeners();
+    uninstallKeyboardActions();
+    uninstallDefaults(); 
+
+    table.remove(rendererPane);
+    rendererPane = null;
+    table = null;
+  }
+
+  /**
+   * Paints a single cell in the table.
+   *
+   * @param g The graphics context to paint in
+   * @param row The row number to paint
+   * @param col The column number to paint
+   * @param bounds The bounds of the cell to paint, assuming a coordinate
+   * system beginning at <code>(0,0)</code> in the upper left corner of the
+   * table
+   * @param rend A cell renderer to paint with
+   */
+  void paintCell(Graphics g, int row, int col, Rectangle bounds,
+                 TableCellRenderer rend)
+  {
+    Component comp = table.prepareRenderer(rend, row, col);
+    rendererPane.paintComponent(g, comp, table, bounds);
+  }
+  
+  /**
+   * Paint the associated table.
+   */
+  public void paint(Graphics gfx, JComponent ignored) 
+  {
+    int ncols = table.getColumnCount();
+    int nrows = table.getRowCount();
+    if (nrows == 0 || ncols == 0)
+      return;
+
+    Rectangle clip = gfx.getClipBounds();
+
+    // Determine the range of cells that are within the clip bounds.
+    Point p1 = new Point(clip.x, clip.y);
+    int c0 = table.columnAtPoint(p1);
+    if (c0 == -1)
+      c0 = 0;
+    int r0 = table.rowAtPoint(p1);
+    if (r0 == -1)
+      r0 = 0;
+    Point p2 = new Point(clip.x + clip.width, clip.y + clip.height);
+    int cn = table.columnAtPoint(p2);
+    if (cn == -1)
+      cn = table.getColumnCount() - 1;
+    int rn = table.rowAtPoint(p2);
+    if (rn == -1)
+      rn = table.getRowCount() - 1;
+
+    int columnMargin = table.getColumnModel().getColumnMargin();
+    int rowMargin = table.getRowMargin();
+
+    TableColumnModel cmodel = table.getColumnModel();
+    int[] widths = new int[cn + 1];
+    for (int i = c0; i <= cn; i++)
+      {
+        widths[i] = cmodel.getColumn(i).getWidth() - columnMargin;
+      }
+    
+    Rectangle bounds = table.getCellRect(r0, c0, false);
+    // The left boundary of the area being repainted.
+    int left = bounds.x;
+    
+    // The top boundary of the area being repainted.
+    int top = bounds.y;
+    
+    // The bottom boundary of the area being repainted.
+    int bottom;
+    
+    // paint the cell contents
+    Color grid = table.getGridColor();    
+    for (int r = r0; r <= rn; ++r)
+      {
+        for (int c = c0; c <= cn; ++c)
+          {
+            bounds.width = widths[c];
+            paintCell(gfx, r, c, bounds, table.getCellRenderer(r, c));
+            bounds.x += widths[c] + columnMargin;
+          }
+        bounds.x = left;
+        bounds.y += table.getRowHeight(r);
+        // Update row height for tables with custom heights.
+        bounds.height = table.getRowHeight(r + 1) - rowMargin;
+      }
+    
+    bottom = bounds.y - rowMargin;
+
+    // paint vertical grid lines
+    if (grid != null && table.getShowVerticalLines())
+      {    
+        Color save = gfx.getColor();
+        gfx.setColor(grid);
+        int x = left - columnMargin;
+        for (int c = c0; c <= cn; ++c)
+          {
+            // The vertical grid is draw right from the cells, so we 
+            // add before drawing.
+            x += widths[c] + columnMargin;
+            gfx.drawLine(x, top, x, bottom);
+          }
+        gfx.setColor(save);
+      }
+
+    // paint horizontal grid lines    
+    if (grid != null && table.getShowHorizontalLines())
+      {    
+        Color save = gfx.getColor();
+        gfx.setColor(grid);
+        int y = top - rowMargin;
+        for (int r = r0; r <= rn; ++r)
+          {
+            // The horizontal grid is draw below the cells, so we 
+            // add before drawing.
+            y += table.getRowHeight(r);
+            gfx.drawLine(left, y, p2.x, y);
+          }
+        gfx.setColor(save);
+      }
+  }
+}

Added: llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/BasicTextAreaUI.java
URL: http://llvm.org/viewvc/llvm-project/llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/BasicTextAreaUI.java?rev=43913&view=auto

==============================================================================
--- llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/BasicTextAreaUI.java (added)
+++ llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/BasicTextAreaUI.java Thu Nov  8 16:56:19 2007
@@ -0,0 +1,116 @@
+/* BasicTextAreaUI.java -- 
+   Copyright (C) 2004, 2006,  Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package javax.swing.plaf.basic;
+
+
+import java.beans.PropertyChangeEvent;
+
+import javax.swing.JComponent;
+import javax.swing.JTextArea;
+import javax.swing.UIDefaults;
+import javax.swing.plaf.ComponentUI;
+import javax.swing.text.Element;
+import javax.swing.text.PlainView;
+import javax.swing.text.View;
+import javax.swing.text.WrappedPlainView;
+
+public class BasicTextAreaUI extends BasicTextUI
+{
+  public static ComponentUI createUI(JComponent comp)
+  {
+    return new BasicTextAreaUI();
+  }
+
+  public BasicTextAreaUI()
+  {
+    // Nothing to do here.
+  }
+
+  /**
+   * Create the view.  Returns a WrappedPlainView if the text area
+   * has lineWrap set to true, otherwise returns a PlainView.  If
+   * lineWrap is true has to check whether the wrap style is word 
+   * or character and return an appropriate WrappedPlainView.
+   * 
+   * @param elem the element to create a View for
+   * @return an appropriate View for the element
+   */
+  public View create(Element elem)
+  {
+    JTextArea comp = (JTextArea) getComponent();
+    if (comp.getLineWrap())
+      {
+        if (comp.getWrapStyleWord())
+          return new WrappedPlainView(elem, true);
+        else
+          return new WrappedPlainView(elem, false);
+      }
+    else
+      return new PlainView(elem);
+  }
+
+  /**
+   * Returns the prefix for entries in the {@link UIDefaults} table.
+   *
+   * @return "TextArea"
+   */
+  protected String getPropertyPrefix()
+  {
+    return "TextArea";
+  }
+  
+  /**
+   * Receives notification whenever one of the text component's bound
+   * properties changes. This changes the view to WrappedPlainView
+   * if setLineWrap(true) is called, and back to PlainView if 
+   * setLineWrap(false) is called.
+   *
+   * @param ev the property change event
+   */
+  protected void propertyChange(PropertyChangeEvent ev)
+  {
+    JTextArea comp = (JTextArea) getComponent();
+    if (ev.getPropertyName() == "lineWrap"
+        || ev.getPropertyName() == "wrapStyleWord")
+      {
+        // Changes the View (without modifying the document or it's listeners).
+        setView(create(textComponent.getDocument().getDefaultRootElement()));
+      }
+  }
+}

Added: llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/BasicTextFieldUI.java
URL: http://llvm.org/viewvc/llvm-project/llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/BasicTextFieldUI.java?rev=43913&view=auto

==============================================================================
--- llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/BasicTextFieldUI.java (added)
+++ llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/BasicTextFieldUI.java Thu Nov  8 16:56:19 2007
@@ -0,0 +1,118 @@
+/* BasicTextFieldUI.java
+   Copyright (C) 2004, 2006,  Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package javax.swing.plaf.basic;
+
+import java.awt.Color;
+import java.beans.PropertyChangeEvent;
+
+import javax.swing.JComponent;
+import javax.swing.UIDefaults;
+import javax.swing.plaf.ColorUIResource;
+import javax.swing.plaf.ComponentUI;
+import javax.swing.text.Element;
+import javax.swing.text.FieldView;
+import javax.swing.text.View;
+
+public class BasicTextFieldUI extends BasicTextUI
+{
+  public BasicTextFieldUI()
+  {
+    super();
+  }
+
+  public View create(Element elem)
+  {
+    return new FieldView(elem);
+  }
+  
+  public static ComponentUI createUI(JComponent c)
+  {
+    return new BasicTextFieldUI();
+  }
+
+  /**
+   * Returns the prefix for entries in the {@link UIDefaults} table.
+   *
+   * @return "TextField"
+   */
+  protected String getPropertyPrefix()
+  {
+    return "TextField";
+  }
+
+  public void installUI(JComponent c)
+  {
+    super.installUI(c);
+  }
+
+  /**
+   * Receives notification whenever one of the text component's bound
+   * properties changes. Here we check for the editable and enabled
+   * properties and adjust the background color accordingly.
+   * 
+   * <p>The colors are only changed if they are not a
+   * <code>ColorUIResource</code>.</p>
+   *
+   * @param event the property change event
+   */
+  protected void propertyChange(PropertyChangeEvent event)
+  {
+    if (event.getPropertyName().equals("editable"))
+      {
+        // Changing the color only if the current background is an instance of
+        // ColorUIResource is the behavior of the RI.
+        if (textComponent.getBackground() instanceof ColorUIResource)
+          {
+            Color c = null;
+            Color old = textComponent.getBackground();
+            String prefix = getPropertyPrefix();
+            if (! textComponent.isEnabled())
+              c = SharedUIDefaults.getColor(prefix + ".disabledBackground");
+            if (c == null && ! textComponent.isEditable())
+              c = SharedUIDefaults.getColor(prefix + ".inactiveBackground");
+            if (c == null)
+              c = SharedUIDefaults.getColor(prefix + ".background");
+            if (c != null && c != old)
+              {
+                textComponent.setBackground(c);
+              }
+          }
+      }
+  }
+}

Added: llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/BasicTextPaneUI.java
URL: http://llvm.org/viewvc/llvm-project/llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/BasicTextPaneUI.java?rev=43913&view=auto

==============================================================================
--- llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/BasicTextPaneUI.java (added)
+++ llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/BasicTextPaneUI.java Thu Nov  8 16:56:19 2007
@@ -0,0 +1,92 @@
+/* BasicTextPaneUI.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., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package javax.swing.plaf.basic;
+
+import java.awt.Color;
+
+import javax.swing.JComponent;
+import javax.swing.JTextPane;
+import javax.swing.plaf.ColorUIResource;
+import javax.swing.UIDefaults;
+import javax.swing.plaf.ComponentUI;
+import javax.swing.text.Style;
+import javax.swing.text.StyleConstants;
+import javax.swing.text.StyleContext;
+
+public class BasicTextPaneUI extends BasicEditorPaneUI
+{
+  public BasicTextPaneUI()
+  {
+    // Do nothing here.
+  }
+
+  public static ComponentUI createUI(JComponent comp)
+  {
+    return new BasicTextPaneUI();
+  }
+
+  /**
+   * Returns the prefix for entries in the {@link UIDefaults} table.
+   *
+   * @return "TextPane"
+   */
+  protected String getPropertyPrefix()
+  {
+    return "TextPane";
+  }
+
+  /**
+   * Installs this UI on the specified <code>JTextPane</code>. This calls the
+   * super implementation and then adds a default style to the text pane.
+   *
+   * @param c the text pane to install the UI to
+   */
+  public void installUI(JComponent c)
+  {
+    super.installUI(c);
+    JTextPane tp = (JTextPane) c;
+    Style defaultStyle = tp.getStyle(StyleContext.DEFAULT_STYLE);
+    defaultStyle.addAttribute(StyleConstants.Foreground,
+                              new ColorUIResource(Color.BLACK));
+    defaultStyle.addAttribute(StyleConstants.FontFamily, "Serif");
+    defaultStyle.addAttribute(StyleConstants.Italic, Boolean.FALSE);
+    defaultStyle.addAttribute(StyleConstants.Bold, Boolean.FALSE);
+    defaultStyle.addAttribute(StyleConstants.FontSize, new Integer(12));
+  }
+}

Added: llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/BasicTextUI.java
URL: http://llvm.org/viewvc/llvm-project/llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/BasicTextUI.java?rev=43913&view=auto

==============================================================================
--- llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/BasicTextUI.java (added)
+++ llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/BasicTextUI.java Thu Nov  8 16:56:19 2007
@@ -0,0 +1,1344 @@
+/* BasicTextUI.java --
+   Copyright (C) 2002, 2003, 2004, 2005, 2006  Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package javax.swing.plaf.basic;
+
+import java.awt.Color;
+import java.awt.Container;
+import java.awt.Dimension;
+import java.awt.Graphics;
+import java.awt.HeadlessException;
+import java.awt.Insets;
+import java.awt.Point;
+import java.awt.Rectangle;
+import java.awt.Shape;
+import java.awt.Toolkit;
+import java.awt.datatransfer.Clipboard;
+import java.awt.datatransfer.StringSelection;
+import java.awt.event.FocusEvent;
+import java.awt.event.FocusListener;
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+
+import javax.swing.Action;
+import javax.swing.ActionMap;
+import javax.swing.InputMap;
+import javax.swing.JComponent;
+import javax.swing.LookAndFeel;
+import javax.swing.SwingConstants;
+import javax.swing.SwingUtilities;
+import javax.swing.TransferHandler;
+import javax.swing.UIManager;
+import javax.swing.event.DocumentEvent;
+import javax.swing.event.DocumentListener;
+import javax.swing.plaf.ActionMapUIResource;
+import javax.swing.plaf.InputMapUIResource;
+import javax.swing.plaf.TextUI;
+import javax.swing.plaf.UIResource;
+import javax.swing.text.AbstractDocument;
+import javax.swing.text.BadLocationException;
+import javax.swing.text.Caret;
+import javax.swing.text.DefaultCaret;
+import javax.swing.text.DefaultEditorKit;
+import javax.swing.text.DefaultHighlighter;
+import javax.swing.text.Document;
+import javax.swing.text.EditorKit;
+import javax.swing.text.Element;
+import javax.swing.text.Highlighter;
+import javax.swing.text.JTextComponent;
+import javax.swing.text.Keymap;
+import javax.swing.text.Position;
+import javax.swing.text.View;
+import javax.swing.text.ViewFactory;
+
+/**
+ * The abstract base class from which the UI classes for Swings text
+ * components are derived. This provides most of the functionality for
+ * the UI classes.
+ *
+ * @author original author unknown
+ * @author Roman Kennke (roman at kennke.org)
+ */
+public abstract class BasicTextUI extends TextUI
+  implements ViewFactory
+{
+  /**
+   * A {@link DefaultCaret} that implements {@link UIResource}.
+   */
+  public static class BasicCaret extends DefaultCaret implements UIResource
+  {
+    public BasicCaret()
+    {
+      // Nothing to do here.
+    }
+  }
+
+  /**
+   * A {@link DefaultHighlighter} that implements {@link UIResource}.
+   */
+  public static class BasicHighlighter extends DefaultHighlighter
+    implements UIResource
+  {
+    public BasicHighlighter()
+    {
+      // Nothing to do here.
+    }
+  }
+
+  /**
+   * This view forms the root of the View hierarchy. However, it delegates
+   * most calls to another View which is the real root of the hierarchy.
+   * The purpose is to make sure that all Views in the hierarchy, including
+   * the (real) root have a well-defined parent to which they can delegate
+   * calls like {@link #preferenceChanged}, {@link #getViewFactory} and
+   * {@link #getContainer}.
+   */
+  private class RootView extends View
+  {
+    /** The real root view. */
+    private View view;
+
+    /**
+     * Creates a new RootView.
+     */
+    public RootView()
+    {
+      super(null);
+    }
+
+    /**
+     * Returns the ViewFactory for this RootView. If the current EditorKit
+     * provides a ViewFactory, this is used. Otherwise the TextUI itself
+     * is returned as a ViewFactory.
+     *
+     * @return the ViewFactory for this RootView
+     */
+    public ViewFactory getViewFactory()
+    {
+      ViewFactory factory = null;
+      EditorKit editorKit = BasicTextUI.this.getEditorKit(getComponent());
+      factory = editorKit.getViewFactory();
+      if (factory == null)
+	factory = BasicTextUI.this;
+      return factory;
+    }
+
+    /**
+     * Indicates that the preferences of one of the child view has changed.
+     * This calls revalidate on the text component.
+     *
+     * @param v the child view which's preference has changed
+     * @param width <code>true</code> if the width preference has changed
+     * @param height <code>true</code> if the height preference has changed
+     */
+    public void preferenceChanged(View v, boolean width, boolean height)
+    {
+      textComponent.revalidate();
+    }
+
+    /**
+     * Sets the real root view.
+     *
+     * @param v the root view to set
+     */
+    public void setView(View v)
+    {
+      if (view != null)
+        view.setParent(null);
+      
+      if (v != null)
+        v.setParent(this);
+
+      view = v;
+    }
+
+    /**
+     * Returns the real root view, regardless of the index.
+     *
+     * @param index not used here
+     *
+     * @return the real root view, regardless of the index.
+     */
+    public View getView(int index)
+    {
+      return view;
+    }
+
+    /**
+     * Returns <code>1</code> since the RootView always contains one
+     * child, that is the real root of the View hierarchy.
+     *
+     * @return <code>1</code> since the RootView always contains one
+     *         child, that is the real root of the View hierarchy
+     */
+    public int getViewCount()
+    {
+      int count = 0;
+      if (view != null)
+        count = 1;
+      return count;
+    }
+
+    /**
+     * Returns the <code>Container</code> that contains this view. This
+     * normally will be the text component that is managed by this TextUI.
+     *
+     * @return the <code>Container</code> that contains this view
+     */
+    public Container getContainer()
+    {
+      return textComponent;
+    }
+
+    /**
+     * Returns the preferred span along the specified <code>axis</code>.
+     * This is delegated to the real root view.
+     *
+     * @param axis the axis for which the preferred span is queried
+     *
+     * @return the preferred span along the axis
+     */
+    public float getPreferredSpan(int axis)
+    {
+      if (view != null)
+	return view.getPreferredSpan(axis);
+
+      return Integer.MAX_VALUE;
+    }
+
+    /**
+     * Paints the view. This is delegated to the real root view.
+     *
+     * @param g the <code>Graphics</code> context to paint to
+     * @param s the allocation for the View
+     */
+    public void paint(Graphics g, Shape s)
+    {
+      if (view != null)
+        {
+          Rectangle b = s.getBounds();
+          view.setSize(b.width, b.height);
+          view.paint(g, s);
+        }
+    }
+
+
+    /**
+     * Maps a position in the document into the coordinate space of the View.
+     * The output rectangle usually reflects the font height but has a width
+     * of zero.
+     *
+     * This is delegated to the real root view.
+     *
+     * @param position the position of the character in the model
+     * @param a the area that is occupied by the view
+     * @param bias either {@link Position.Bias#Forward} or
+     *        {@link Position.Bias#Backward} depending on the preferred
+     *        direction bias. If <code>null</code> this defaults to
+     *        <code>Position.Bias.Forward</code>
+     *
+     * @return a rectangle that gives the location of the document position
+     *         inside the view coordinate space
+     *
+     * @throws BadLocationException if <code>pos</code> is invalid
+     * @throws IllegalArgumentException if b is not one of the above listed
+     *         valid values
+     */
+    public Shape modelToView(int position, Shape a, Position.Bias bias)
+      throws BadLocationException
+    {
+      return view.modelToView(position, a, bias);
+    }
+
+    /**
+     * Maps coordinates from the <code>View</code>'s space into a position
+     * in the document model.
+     *
+     * @param x the x coordinate in the view space
+     * @param y the y coordinate in the view space
+     * @param a the allocation of this <code>View</code>
+     * @param b the bias to use
+     *
+     * @return the position in the document that corresponds to the screen
+     *         coordinates <code>x, y</code>
+     */
+    public int viewToModel(float x, float y, Shape a, Position.Bias[] b)
+    {
+      return view.viewToModel(x, y, a, b);
+    }
+
+    /**
+     * Notification about text insertions. These are forwarded to the
+     * real root view.
+     *
+     * @param ev the DocumentEvent describing the change
+     * @param shape the current allocation of the view's display
+     * @param vf the ViewFactory to use for creating new Views
+     */
+    public void insertUpdate(DocumentEvent ev, Shape shape, ViewFactory vf)
+    {
+      view.insertUpdate(ev, shape, vf);
+    }
+
+    /**
+     * Notification about text removals. These are forwarded to the
+     * real root view.
+     *
+     * @param ev the DocumentEvent describing the change
+     * @param shape the current allocation of the view's display
+     * @param vf the ViewFactory to use for creating new Views
+     */
+    public void removeUpdate(DocumentEvent ev, Shape shape, ViewFactory vf)
+    {
+      view.removeUpdate(ev, shape, vf);
+    }
+
+    /**
+     * Notification about text changes. These are forwarded to the
+     * real root view.
+     *
+     * @param ev the DocumentEvent describing the change
+     * @param shape the current allocation of the view's display
+     * @param vf the ViewFactory to use for creating new Views
+     */
+    public void changedUpdate(DocumentEvent ev, Shape shape, ViewFactory vf)
+    {
+      view.changedUpdate(ev, shape, vf);
+    }
+
+    /**
+     * Returns the document position that is (visually) nearest to the given
+     * document position <code>pos</code> in the given direction <code>d</code>.
+     *
+     * @param pos the document position
+     * @param b the bias for <code>pos</code>
+     * @param a the allocation for the view
+     * @param d the direction, must be either {@link SwingConstants#NORTH},
+     *        {@link SwingConstants#SOUTH}, {@link SwingConstants#WEST} or
+     *        {@link SwingConstants#EAST}
+     * @param biasRet an array of {@link Position.Bias} that can hold at least
+     *        one element, which is filled with the bias of the return position
+     *        on method exit
+     *
+     * @return the document position that is (visually) nearest to the given
+     *         document position <code>pos</code> in the given direction
+     *         <code>d</code>
+     *
+     * @throws BadLocationException if <code>pos</code> is not a valid offset in
+     *         the document model
+     */
+    public int getNextVisualPositionFrom(int pos, Position.Bias b, Shape a,
+                                         int d, Position.Bias[] biasRet)
+      throws BadLocationException
+    {
+      return view.getNextVisualPositionFrom(pos, b, a, d, biasRet);
+    }
+
+    /**
+     * Returns the startOffset of this view, which is always the beginning
+     * of the document.
+     *
+     * @return the startOffset of this view
+     */
+    public int getStartOffset()
+    {
+      return 0;
+    }
+
+    /**
+     * Returns the endOffset of this view, which is always the end
+     * of the document.
+     *
+     * @return the endOffset of this view
+     */
+    public int getEndOffset()
+    {
+      return getDocument().getLength();
+    }
+
+    /**
+     * Returns the document associated with this view.
+     *
+     * @return the document associated with this view
+     */
+    public Document getDocument()
+    {
+      return textComponent.getDocument();
+    }
+  }
+
+  /**
+   * Receives notifications when properties of the text component change.
+   */
+  private class PropertyChangeHandler implements PropertyChangeListener
+  {
+    /**
+     * Notifies when a property of the text component changes.
+     *
+     * @param event the PropertyChangeEvent describing the change
+     */
+    public void propertyChange(PropertyChangeEvent event)
+    {
+      if (event.getPropertyName().equals("document"))
+        {
+          // Document changed.
+          Object oldValue = event.getOldValue();
+          if (oldValue != null)
+            {
+              Document oldDoc = (Document) oldValue;
+              oldDoc.removeDocumentListener(documentHandler);
+            }
+          Object newValue = event.getNewValue();
+          if (newValue != null)
+            {
+              Document newDoc = (Document) newValue;
+              newDoc.addDocumentListener(documentHandler);
+            }
+          modelChanged();
+        }
+
+      BasicTextUI.this.propertyChange(event);
+    }
+  }
+
+  /**
+   * Listens for changes on the underlying model and forwards notifications
+   * to the View. This also updates the caret position of the text component.
+   *
+   * TODO: Maybe this should somehow be handled through EditorKits
+   */
+  class DocumentHandler implements DocumentListener
+  {
+    /**
+     * Notification about a document change event.
+     *
+     * @param ev the DocumentEvent describing the change
+     */
+    public void changedUpdate(DocumentEvent ev)
+    {
+      // Updates are forwarded to the View even if 'getVisibleEditorRect'
+      // method returns null. This means the View classes have to be
+      // aware of that possibility.
+      rootView.changedUpdate(ev, getVisibleEditorRect(),
+                             rootView.getViewFactory());
+    }
+
+    /**
+     * Notification about a document insert event.
+     *
+     * @param ev the DocumentEvent describing the insertion
+     */
+    public void insertUpdate(DocumentEvent ev)
+    {
+      // Updates are forwarded to the View even if 'getVisibleEditorRect'
+      // method returns null. This means the View classes have to be
+      // aware of that possibility.
+      rootView.insertUpdate(ev, getVisibleEditorRect(),
+                            rootView.getViewFactory());
+    }
+
+    /**
+     * Notification about a document removal event.
+     *
+     * @param ev the DocumentEvent describing the removal
+     */
+    public void removeUpdate(DocumentEvent ev)
+    {
+      // Updates are forwarded to the View even if 'getVisibleEditorRect'
+      // method returns null. This means the View classes have to be
+      // aware of that possibility.
+      rootView.removeUpdate(ev, getVisibleEditorRect(),
+                            rootView.getViewFactory());
+    }
+  }
+
+  /**
+   * The EditorKit used by this TextUI.
+   */
+  // FIXME: should probably be non-static.
+  static EditorKit kit = new DefaultEditorKit();
+
+  /**
+   * The root view.
+   */
+  RootView rootView = new RootView();
+
+  /**
+   * The text component that we handle.
+   */
+  JTextComponent textComponent;
+
+  /**
+   * Receives notification when the model changes.
+   */
+  private PropertyChangeHandler updateHandler = new PropertyChangeHandler();
+
+  /** The DocumentEvent handler. */
+  DocumentHandler documentHandler = new DocumentHandler();
+
+  /**
+   * Creates a new <code>BasicTextUI</code> instance.
+   */
+  public BasicTextUI()
+  {
+    // Nothing to do here.
+  }
+
+  /**
+   * Creates a {@link Caret} that should be installed into the text component.
+   *
+   * @return a caret that should be installed into the text component
+   */
+  protected Caret createCaret()
+  {
+    return new BasicCaret();
+  }
+
+  /**
+   * Creates a {@link Highlighter} that should be installed into the text
+   * component.
+   *
+   * @return a <code>Highlighter</code> for the text component
+   */
+  protected Highlighter createHighlighter()
+  {
+    return new BasicHighlighter();
+  }
+
+  /**
+   * The text component that is managed by this UI.
+   *
+   * @return the text component that is managed by this UI
+   */
+  protected final JTextComponent getComponent()
+  {
+    return textComponent;
+  }
+
+  /**
+   * Installs this UI on the text component.
+   *
+   * @param c the text component on which to install the UI
+   */
+  public void installUI(final JComponent c)
+  {
+    textComponent = (JTextComponent) c;
+    installDefaults();
+    textComponent.addPropertyChangeListener(updateHandler);
+    Document doc = textComponent.getDocument();
+    if (doc == null)
+      {
+        doc = getEditorKit(textComponent).createDefaultDocument();
+        textComponent.setDocument(doc);
+      }
+    else
+      {
+        doc.addDocumentListener(documentHandler);
+        modelChanged();
+      }
+
+    installListeners();
+    installKeyboardActions();
+  }
+
+  /**
+   * Installs UI defaults on the text components.
+   */
+  protected void installDefaults()
+  {
+    String prefix = getPropertyPrefix();
+    // Install the standard properties.
+    LookAndFeel.installColorsAndFont(textComponent, prefix + ".background",
+                                     prefix + ".foreground", prefix + ".font");
+    LookAndFeel.installBorder(textComponent, prefix + ".border");
+    textComponent.setMargin(UIManager.getInsets(prefix + ".margin"));
+
+    // Some additional text component only properties.
+    Color color = textComponent.getCaretColor();
+    if (color == null || color instanceof UIResource)
+      {
+        color = UIManager.getColor(prefix + ".caretForeground");
+        textComponent.setCaretColor(color);
+      }
+
+    // Fetch the colors for enabled/disabled text components.
+    color = textComponent.getDisabledTextColor();
+    if (color == null || color instanceof UIResource)
+      {
+        color = UIManager.getColor(prefix + ".inactiveBackground");
+        textComponent.setDisabledTextColor(color);
+      }
+    color = textComponent.getSelectedTextColor();
+    if (color == null || color instanceof UIResource)
+      {
+        color = UIManager.getColor(prefix  + ".selectionForeground");
+        textComponent.setSelectedTextColor(color);
+      }
+    color = textComponent.getSelectionColor();
+    if (color == null || color instanceof UIResource)
+      {
+        color = UIManager.getColor(prefix  + ".selectionBackground");
+        textComponent.setSelectionColor(color);    
+      }
+
+    Insets margin = textComponent.getMargin();
+    if (margin == null || margin instanceof UIResource)
+      {
+        margin = UIManager.getInsets(prefix + ".margin");
+        textComponent.setMargin(margin);
+      }
+
+    Caret caret = textComponent.getCaret();
+    if (caret == null || caret instanceof UIResource)
+      {
+        caret = createCaret();
+        textComponent.setCaret(caret);
+        caret.setBlinkRate(UIManager.getInt(prefix + ".caretBlinkRate"));
+      }
+
+    Highlighter highlighter = textComponent.getHighlighter();
+    if (highlighter == null || highlighter instanceof UIResource)
+      textComponent.setHighlighter(createHighlighter());
+
+  }
+
+  /**
+   * This FocusListener triggers repaints on focus shift.
+   */
+  private FocusListener focuslistener = new FocusListener() {
+      public void focusGained(FocusEvent e) 
+      {
+        textComponent.repaint();
+      }
+      public void focusLost(FocusEvent e)
+      {
+        textComponent.repaint();
+        
+        // Integrates Swing text components with the system clipboard:
+        // The idea is that if one wants to copy text around X11-style
+        // (select text and middle-click in the target component) the focus
+        // will move to the new component which gives the old focus owner the
+        // possibility to paste its selection into the clipboard.
+        if (!e.isTemporary()
+            && textComponent.getSelectionStart()
+               != textComponent.getSelectionEnd())
+          {
+            SecurityManager sm = System.getSecurityManager();
+            try
+              {
+                if (sm != null)
+                  sm.checkSystemClipboardAccess();
+                
+                Clipboard cb = Toolkit.getDefaultToolkit().getSystemSelection();
+                if (cb != null)
+                  {
+                    StringSelection selection = new StringSelection(
+                        textComponent.getSelectedText());
+                    cb.setContents(selection, selection);
+                  }
+              }
+            catch (SecurityException se)
+              {
+                // Not allowed to access the clipboard: Ignore and
+                // do not access it.
+              }
+            catch (HeadlessException he)
+              {
+                // There is no AWT: Ignore and do not access the
+                // clipboard.
+              }
+            catch (IllegalStateException ise)
+            {
+                // Clipboard is currently unavaible.
+            }
+          }
+      }
+    };
+
+  /**
+   * Install all listeners on the text component.
+   */
+  protected void installListeners()
+  {
+    textComponent.addFocusListener(focuslistener);
+  }
+
+  /**
+   * Returns the name of the keymap for this type of TextUI.
+   * 
+   * This is implemented so that the classname of this TextUI
+   * without the package prefix is returned. This way subclasses
+   * don't have to override this method.
+   * 
+   * @return the name of the keymap for this TextUI
+   */
+  protected String getKeymapName()
+  {
+    String fullClassName = getClass().getName();
+    int index = fullClassName.lastIndexOf('.');
+    String className = fullClassName.substring(index + 1);
+    return className;
+  }
+
+  /**
+   * Creates the {@link Keymap} that is installed on the text component.
+   *
+   * @return the {@link Keymap} that is installed on the text component
+   */
+  protected Keymap createKeymap()
+  {
+    String keymapName = getKeymapName();
+    Keymap keymap = JTextComponent.getKeymap(keymapName);
+    if (keymap == null)
+      {
+        Keymap parentMap =
+          JTextComponent.getKeymap(JTextComponent.DEFAULT_KEYMAP);
+        keymap = JTextComponent.addKeymap(keymapName, parentMap);
+        Object val = UIManager.get(getPropertyPrefix() + ".keyBindings");
+        if (val != null && val instanceof JTextComponent.KeyBinding[])
+          {
+            JTextComponent.KeyBinding[] bindings =
+              (JTextComponent.KeyBinding[]) val;
+            JTextComponent.loadKeymap(keymap, bindings,
+                                      getComponent().getActions());
+          }
+      }
+    return keymap;
+  }
+
+  /**
+   * Installs the keyboard actions on the text components.
+   */
+  protected void installKeyboardActions()
+  {
+    // This is only there for backwards compatibility.
+    textComponent.setKeymap(createKeymap());
+
+    // load any bindings for the newer InputMap / ActionMap interface
+    SwingUtilities.replaceUIInputMap(textComponent, JComponent.WHEN_FOCUSED,
+                                     getInputMap());
+    SwingUtilities.replaceUIActionMap(textComponent, getActionMap());
+  }
+  
+  /**
+   * Creates an ActionMap to be installed on the text component.
+   * 
+   * @return an ActionMap to be installed on the text component
+   */
+  private ActionMap getActionMap()
+  {
+    // Note: There are no .actionMap entries in the standard L&Fs. However,
+    // with the RI it is possible to install action maps via such keys, so
+    // we must load them too. It can be observed that when there is no
+    // .actionMap entry in the UIManager, one gets installed after a text
+    // component of that type has been loaded.
+    String prefix = getPropertyPrefix();
+    String amName = prefix + ".actionMap";
+    ActionMap am = (ActionMap) UIManager.get(amName);
+    if (am == null)
+      {
+        am = createActionMap();
+        UIManager.put(amName, am);
+      }
+
+    ActionMap map = new ActionMapUIResource();
+    map.setParent(am);
+
+    return map;
+  }
+
+  /**
+   * Creates a default ActionMap for text components that have no UI default
+   * for this (the standard for the built-in L&Fs). The ActionMap is copied
+   * from the text component's getActions() method.
+   *
+   * @returna default ActionMap
+   */
+  private ActionMap createActionMap()
+  {
+    ActionMap am = new ActionMapUIResource();
+    Action[] actions = textComponent.getActions();
+    for (int i = actions.length - 1; i >= 0; i--)
+      {
+        Action action = actions[i];
+        am.put(action.getValue(Action.NAME), action);
+      }
+    // Add TransferHandler's actions here. They don't seem to be in the
+    // JTextComponent's default actions, and I can't make up a better place
+    // to add them.
+    Action copyAction = TransferHandler.getCopyAction();
+    am.put(copyAction.getValue(Action.NAME), copyAction);
+    Action cutAction = TransferHandler.getCutAction();
+    am.put(cutAction.getValue(Action.NAME), cutAction);
+    Action pasteAction = TransferHandler.getPasteAction();
+    am.put(pasteAction.getValue(Action.NAME), pasteAction);
+
+    return am;
+  }
+
+  /**
+   * Gets the input map for the specified <code>condition</code>.
+   *
+   * @return the InputMap for the specified condition
+   */
+  private InputMap getInputMap()
+  {
+    InputMap im = new InputMapUIResource();
+    String prefix = getPropertyPrefix();
+    InputMap shared =
+      (InputMap) SharedUIDefaults.get(prefix + ".focusInputMap");
+    if (shared != null)
+      im.setParent(shared);
+    return im;
+  }
+
+  /**
+   * Uninstalls this TextUI from the text component.
+   *
+   * @param component the text component to uninstall the UI from
+   */
+  public void uninstallUI(final JComponent component)
+  {
+    super.uninstallUI(component);
+    rootView.setView(null);
+
+    uninstallDefaults();
+    uninstallListeners();
+    uninstallKeyboardActions();
+
+    textComponent = null;
+  }
+
+  /**
+   * Uninstalls all default properties that have previously been installed by
+   * this UI.
+   */
+  protected void uninstallDefaults()
+  {
+    // Do nothing here.
+  }
+
+  /**
+   * Uninstalls all listeners that have previously been installed by
+   * this UI.
+   */
+  protected void uninstallListeners()
+  {
+    textComponent.removeFocusListener(focuslistener);
+  }
+
+  /**
+   * Uninstalls all keyboard actions that have previously been installed by
+   * this UI.
+   */
+  protected void uninstallKeyboardActions()
+  {
+    SwingUtilities.replaceUIInputMap(textComponent, JComponent.WHEN_FOCUSED, 
+                                     null);
+    SwingUtilities.replaceUIActionMap(textComponent, null);
+  }
+
+  /**
+   * Returns the property prefix by which the text component's UIDefaults
+   * are looked up.
+   *
+   * @return the property prefix by which the text component's UIDefaults
+   *     are looked up
+   */
+  protected abstract String getPropertyPrefix();
+
+  /**
+   * Returns the preferred size of the text component.
+   *
+   * @param c not used here
+   *
+   * @return the preferred size of the text component
+   */
+  public Dimension getPreferredSize(JComponent c)
+  {
+    View v = getRootView(textComponent);
+
+    float w = v.getPreferredSpan(View.X_AXIS);
+    float h = v.getPreferredSpan(View.Y_AXIS);
+
+    Insets i = c.getInsets();
+    return new Dimension((int) w + i.left + i.right,
+                         (int) h + i.top + i.bottom);
+  }
+
+  /**
+   * Returns the maximum size for text components that use this UI.
+   *
+   * This returns (Integer.MAX_VALUE, Integer.MAX_VALUE).
+   *
+   * @param c not used here
+   *
+   * @return the maximum size for text components that use this UI
+   */
+  public Dimension getMaximumSize(JComponent c)
+  {
+    // Sun's implementation returns Integer.MAX_VALUE here, so do we.
+    return new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE);
+  }
+
+  /**
+   * Returns the minimum size for text components. This returns the size
+   * of the component's insets.
+   *
+   * @return the minimum size for text components
+   */
+  public Dimension getMinimumSize(JComponent c)
+  {
+    Insets i = c.getInsets();
+    return new Dimension(i.left + i.right, i.top + i.bottom);
+  }
+
+  /**
+   * Paints the text component. This acquires a read lock on the model and then
+   * calls {@link #paintSafely(Graphics)} in order to actually perform the
+   * painting.
+   *
+   * @param g the <code>Graphics</code> context to paint to
+   * @param c not used here
+   */
+  public final void paint(Graphics g, JComponent c)
+  {
+    try
+      {
+        Document doc = textComponent.getDocument();
+        if (doc instanceof AbstractDocument)
+          {
+            AbstractDocument aDoc = (AbstractDocument) doc;
+            aDoc.readLock();
+          }
+        
+        paintSafely(g);
+      }
+    finally
+      {
+        Document doc = textComponent.getDocument();
+        if (doc instanceof AbstractDocument)
+          {
+            AbstractDocument aDoc = (AbstractDocument) doc;
+            aDoc.readUnlock();
+          }
+      }
+  }
+
+  /**
+   * This paints the text component while beeing sure that the model is not
+   * modified while painting.
+   *
+   * The following is performed in this order:
+   * <ol>
+   * <li>If the text component is opaque, the background is painted by
+   * calling {@link #paintBackground(Graphics)}.</li>
+   * <li>If there is a highlighter, the highlighter is painted.</li>
+   * <li>The view hierarchy is painted.</li>
+   * <li>The Caret is painter.</li>
+   * </ol>
+   *
+   * @param g the <code>Graphics</code> context to paint to
+   */
+  protected void paintSafely(Graphics g)
+  {
+    Caret caret = textComponent.getCaret();
+    Highlighter highlighter = textComponent.getHighlighter();
+
+    if (textComponent.isOpaque())
+      paintBackground(g);
+
+    // Try painting with the highlighter without checking whether there
+    // is a selection because a highlighter can be used to do more than
+    // marking selected text.
+    if (highlighter != null)
+      {
+        // Handle restoring of the color here to prevent
+        // drawing problems when the Highlighter implementor
+        // forgets to restore it.
+        Color oldColor = g.getColor();
+        highlighter.paint(g);
+        g.setColor(oldColor);
+      }
+      
+
+    rootView.paint(g, getVisibleEditorRect());
+
+    if (caret != null && textComponent.hasFocus())
+      caret.paint(g);
+  }
+
+  /**
+   * Paints the background of the text component.
+   *
+   * @param g the <code>Graphics</code> context to paint to
+   */
+  protected void paintBackground(Graphics g)
+  {
+    Color old = g.getColor();
+    g.setColor(textComponent.getBackground());
+    g.fillRect(0, 0, textComponent.getWidth(), textComponent.getHeight());
+    g.setColor(old);
+  }
+
+  /**
+   * Overridden for better control over background painting. This now simply
+   * calls {@link #paint} and this delegates the background painting to
+   * {@link #paintBackground}.
+   *
+   * @param g the graphics to use
+   * @param c the component to be painted
+   */
+  public void update(Graphics g, JComponent c)
+  {
+    paint(g, c);
+  }
+
+  /**
+   * Marks the specified range inside the text component's model as
+   * damaged and queues a repaint request.
+   *
+   * @param t the text component
+   * @param p0 the start location inside the document model of the range that
+   *        is damaged
+   * @param p1 the end location inside the document model of the range that
+   *        is damaged
+   */
+  public void damageRange(JTextComponent t, int p0, int p1)
+  {
+    damageRange(t, p0, p1, Position.Bias.Forward, Position.Bias.Backward);
+  }
+
+  /**
+   * Marks the specified range inside the text component's model as
+   * damaged and queues a repaint request. This variant of this method
+   * allows a {@link Position.Bias} object to be specified for the start
+   * and end location of the range.
+   *
+   * @param t the text component
+   * @param p0 the start location inside the document model of the range that
+   *        is damaged
+   * @param p1 the end location inside the document model of the range that
+   *        is damaged
+   * @param firstBias the bias for the start location
+   * @param secondBias the bias for the end location
+   */
+  public void damageRange(JTextComponent t, int p0, int p1,
+                          Position.Bias firstBias, Position.Bias secondBias)
+  {
+    Rectangle alloc = getVisibleEditorRect();
+    if (alloc != null)
+      {
+        Document doc = t.getDocument();
+
+        // Acquire lock here to avoid structural changes in between.
+        if (doc instanceof AbstractDocument)
+          ((AbstractDocument) doc).readLock();
+        try
+          {
+            rootView.setSize(alloc.width, alloc.height);
+            Shape damage = rootView.modelToView(p0, firstBias, p1, secondBias,
+                                                alloc);
+            Rectangle r = damage instanceof Rectangle ? (Rectangle) damage
+                                                      : damage.getBounds();
+            textComponent.repaint(r.x, r.y, r.width, r.height);
+          }
+        catch (BadLocationException ex)
+          {
+            // Lets ignore this as it causes no serious problems.
+            // For debugging, comment this out.
+            // ex.printStackTrace();
+          }
+        finally
+          {
+            // Release lock.
+            if (doc instanceof AbstractDocument)
+              ((AbstractDocument) doc).readUnlock();
+          }
+      }
+  }
+
+  /**
+   * Returns the {@link EditorKit} used for the text component that is managed
+   * by this UI.
+   *
+   * @param t the text component
+   *
+   * @return the {@link EditorKit} used for the text component that is managed
+   *         by this UI
+   */
+  public EditorKit getEditorKit(JTextComponent t)
+  {
+    return kit;
+  }
+
+  /**
+   * Gets the next position inside the document model that is visible on
+   * screen, starting from <code>pos</code>.
+   *
+   * @param t the text component
+   * @param pos the start positionn
+   * @param b the bias for pos
+   * @param direction the search direction
+   * @param biasRet filled by the method to indicate the bias of the return
+   *        value
+   *
+   * @return the next position inside the document model that is visible on
+   *         screen
+   */
+  public int getNextVisualPositionFrom(JTextComponent t, int pos,
+                                       Position.Bias b, int direction,
+                                       Position.Bias[] biasRet)
+    throws BadLocationException
+  {
+    // A comment in the spec of NavigationFilter.getNextVisualPositionFrom()
+    // suggests that this method should be implemented by forwarding the call
+    // the root view.
+    return rootView.getNextVisualPositionFrom(pos, b,
+                                              getVisibleEditorRect(),
+                                              direction, biasRet);
+  }
+
+  /**
+   * Returns the root {@link View} of a text component.
+   *
+   * @return the root {@link View} of a text component
+   */
+  public View getRootView(JTextComponent t)
+  {
+    return rootView;
+  }
+
+  /**
+   * Maps a position in the document into the coordinate space of the View.
+   * The output rectangle usually reflects the font height but has a width
+   * of zero. A bias of {@link Position.Bias#Forward} is used in this method.
+   *
+   * @param t the text component
+   * @param pos the position of the character in the model
+   *
+   * @return a rectangle that gives the location of the document position
+   *         inside the view coordinate space
+   *
+   * @throws BadLocationException if <code>pos</code> is invalid
+   * @throws IllegalArgumentException if b is not one of the above listed
+   *         valid values
+   */
+  public Rectangle modelToView(JTextComponent t, int pos)
+    throws BadLocationException
+  {
+    return modelToView(t, pos, Position.Bias.Forward);
+  }
+
+  /**
+   * Maps a position in the document into the coordinate space of the View.
+   * The output rectangle usually reflects the font height but has a width
+   * of zero.
+   *
+   * @param t the text component
+   * @param pos the position of the character in the model
+   * @param bias either {@link Position.Bias#Forward} or
+   *        {@link Position.Bias#Backward} depending on the preferred
+   *        direction bias. If <code>null</code> this defaults to
+   *        <code>Position.Bias.Forward</code>
+   *
+   * @return a rectangle that gives the location of the document position
+   *         inside the view coordinate space
+   *
+   * @throws BadLocationException if <code>pos</code> is invalid
+   * @throws IllegalArgumentException if b is not one of the above listed
+   *         valid values
+   */
+  public Rectangle modelToView(JTextComponent t, int pos, Position.Bias bias)
+    throws BadLocationException
+  {
+    // We need to read-lock here because we depend on the document
+    // structure not beeing changed in between.
+    Document doc = textComponent.getDocument();
+    if (doc instanceof AbstractDocument)
+      ((AbstractDocument) doc).readLock();
+    Rectangle rect = null;
+    try
+      {
+        Rectangle r = getVisibleEditorRect();
+        if (r != null)
+          {
+            rootView.setSize(r.width, r.height);
+            Shape s = rootView.modelToView(pos, r, bias);
+            if (s != null)
+              rect = s.getBounds();
+          }
+      }
+    finally
+      {
+        if (doc instanceof AbstractDocument)
+          ((AbstractDocument) doc).readUnlock();
+      }
+    return rect;
+  }
+
+  /**
+   * Maps a point in the <code>View</code> coordinate space to a position
+   * inside a document model.
+   *
+   * @param t the text component
+   * @param pt the point to be mapped
+   *
+   * @return the position inside the document model that corresponds to
+   *     <code>pt</code>
+   */
+  public int viewToModel(JTextComponent t, Point pt)
+  {
+    return viewToModel(t, pt, null);
+  }
+
+  /**
+   * Maps a point in the <code>View</code> coordinate space to a position
+   * inside a document model.
+   *
+   * @param t the text component
+   * @param pt the point to be mapped
+   * @param biasReturn filled in by the method to indicate the bias of the
+   *        return value
+   *
+   * @return the position inside the document model that corresponds to
+   *     <code>pt</code>
+   */
+  public int viewToModel(JTextComponent t, Point pt, Position.Bias[] biasReturn)
+  {
+    return rootView.viewToModel(pt.x, pt.y, getVisibleEditorRect(), biasReturn);
+  }
+
+  /**
+   * Creates a {@link View} for the specified {@link Element}.
+   *
+   * @param elem the <code>Element</code> to create a <code>View</code> for
+   *
+   * @see ViewFactory
+   */
+  public View create(Element elem)
+  {
+    // Subclasses have to implement this to get this functionality.
+    return null;
+  }
+
+  /**
+   * Creates a {@link View} for the specified {@link Element}.
+   *
+   * @param elem the <code>Element</code> to create a <code>View</code> for
+   * @param p0 the start offset
+   * @param p1 the end offset
+   *
+   * @see ViewFactory
+   */
+  public View create(Element elem, int p0, int p1)
+  {
+    // Subclasses have to implement this to get this functionality.
+    return null;
+  }
+
+  /**
+   * Returns the allocation to give the root view.
+   *
+   * @return the allocation to give the root view
+   *
+   * @specnote The allocation has nothing to do with visibility. According
+   *           to the specs the naming of this method is unfortunate and
+   *           has historical reasons
+   */
+  protected Rectangle getVisibleEditorRect()
+  {
+    int width = textComponent.getWidth();
+    int height = textComponent.getHeight();
+
+    // Return null if the component has no valid size.
+    if (width <= 0 || height <= 0)
+      return null;
+	
+    Insets insets = textComponent.getInsets();
+    return new Rectangle(insets.left, insets.top,
+			 width - insets.left - insets.right,
+			 height - insets.top - insets.bottom);
+  }
+
+  /**
+   * Sets the root view for the text component.
+   *
+   * @param view the <code>View</code> to be set as root view
+   */
+  protected final void setView(View view)
+  {
+    rootView.setView(view);
+    textComponent.revalidate();
+    textComponent.repaint();
+  }
+
+  /**
+   * Indicates that the model of a text component has changed. This
+   * triggers a rebuild of the view hierarchy.
+   */
+  protected void modelChanged()
+  {
+    if (textComponent == null || rootView == null) 
+      return;
+    ViewFactory factory = rootView.getViewFactory();
+    if (factory == null) 
+      return;
+    Document doc = textComponent.getDocument();
+    if (doc == null)
+      return;
+    Element elem = doc.getDefaultRootElement();
+    if (elem == null)
+      return;
+    View view = factory.create(elem);
+    setView(view);
+  }
+
+  /**
+   * Receives notification whenever one of the text component's bound
+   * properties changes. This default implementation does nothing.
+   * It is a hook that enables subclasses to react to property changes
+   * on the text component.
+   *
+   * @param ev the property change event
+   */
+  protected void propertyChange(PropertyChangeEvent ev)
+  {
+    // The default implementation does nothing.
+  }
+}

Added: llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/BasicToggleButtonUI.java
URL: http://llvm.org/viewvc/llvm-project/llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/BasicToggleButtonUI.java?rev=43913&view=auto

==============================================================================
--- llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/BasicToggleButtonUI.java (added)
+++ llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/BasicToggleButtonUI.java Thu Nov  8 16:56:19 2007
@@ -0,0 +1,134 @@
+/* BasicToggleButtonUI.java
+   Copyright (C) 2002, 2004, 2005, 2006, Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package javax.swing.plaf.basic;
+
+import java.awt.Font;
+import java.awt.Graphics;
+import java.awt.Rectangle;
+
+import javax.swing.AbstractButton;
+import javax.swing.JComponent;
+import javax.swing.JToggleButton;
+import javax.swing.SwingUtilities;
+import javax.swing.UIManager;
+import javax.swing.plaf.ComponentUI;
+
+/**
+ * A UI delegate for the {@link JToggleButton} component.
+ */
+public class BasicToggleButtonUI extends BasicButtonUI
+{
+  
+  /**
+   * Returns a UI delegate for the specified component.
+   * 
+   * @param component  the component (should be an instance of 
+   *     {@link JToggleButton}).
+   *     
+   * @return An instance of <code>BasicToggleButtonUI</code>.
+   */
+  public static ComponentUI createUI(JComponent component)
+  {
+    return new BasicToggleButtonUI();
+  }    
+
+  /**
+   * Returns the prefix for entries in the {@link UIManager} defaults table 
+   * (<code>"ToggleButton."</code> in this case).
+   *
+   * @return <code>"ToggleButton."</code>
+   */
+  protected String getPropertyPrefix()
+  {
+    return "ToggleButton.";
+  }
+
+  /**
+   * Paint the component, which is an {@link AbstractButton}, according to 
+   * its current state.
+   *
+   * @param g The graphics context to paint with
+   * @param c The component to paint the state of
+   */
+  public void paint(Graphics g, JComponent c)
+  {      
+    AbstractButton b = (AbstractButton) c;
+
+    Rectangle tr = new Rectangle();
+    Rectangle ir = new Rectangle();
+    Rectangle vr = new Rectangle();
+
+    Font f = c.getFont();
+
+    g.setFont(f);
+
+    if (b.isBorderPainted())
+      SwingUtilities.calculateInnerArea(b, vr);
+    else
+      vr = SwingUtilities.getLocalBounds(b);
+    String text = SwingUtilities.layoutCompoundLabel(c, g.getFontMetrics(f), 
+        b.getText(), currentIcon(b), b.getVerticalAlignment(), 
+        b.getHorizontalAlignment(), b.getVerticalTextPosition(), 
+        b.getHorizontalTextPosition(), vr, ir, tr, b.getIconTextGap() 
+        + defaultTextShiftOffset);
+
+    if ((b.getModel().isArmed() && b.getModel().isPressed()) 
+        || b.isSelected())
+      paintButtonPressed(g, b);
+
+    paintIcon(g, b, ir);
+    if (text != null)
+      paintText(g, b, tr, text);
+    if (b.isFocusOwner() && b.isFocusPainted())
+      paintFocus(g, b, vr, tr, ir);
+  }
+
+  /**
+   * Paints the icon for the toggle button. This delegates to
+   * {@link BasicButtonUI#paintIcon(Graphics, JComponent, Rectangle)}.
+   *
+   * @param g the graphics context
+   * @param b the button to paint the icon for
+   * @param iconRect the area allocated for the icon
+   */
+  protected void paintIcon(Graphics g, AbstractButton b, Rectangle iconRect)
+  {
+    super.paintIcon(g, b, iconRect);
+  }
+}

Added: llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/BasicToolBarSeparatorUI.java
URL: http://llvm.org/viewvc/llvm-project/llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/BasicToolBarSeparatorUI.java?rev=43913&view=auto

==============================================================================
--- llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/BasicToolBarSeparatorUI.java (added)
+++ llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/BasicToolBarSeparatorUI.java Thu Nov  8 16:56:19 2007
@@ -0,0 +1,124 @@
+/* BasicToolBarSeparatorUI.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., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package javax.swing.plaf.basic;
+
+import java.awt.Dimension;
+import java.awt.Graphics;
+
+import javax.swing.JComponent;
+import javax.swing.JSeparator;
+import javax.swing.UIManager;
+import javax.swing.plaf.ComponentUI;
+
+/**
+ * The Basic Look and Feel UI delegate for Separator.
+ */
+public class BasicToolBarSeparatorUI extends BasicSeparatorUI
+{
+  private transient Dimension size;
+
+  /**
+   * Creates a new UI delegate for the given JComponent.
+   *
+   * @param c The JComponent to create a delegate for.
+   *
+   * @return A new BasicToolBarSeparatorUI.
+   */
+  public static ComponentUI createUI(JComponent c)
+  {
+    return new BasicToolBarSeparatorUI();
+  }
+
+  /**
+   * This method installs the defaults that are given by the Basic L&F.
+   *
+   * @param s The Separator that is being installed.
+   */
+  protected void installDefaults(JSeparator s)
+  {
+    size = UIManager.getDimension("ToolBar.separatorSize");
+  }
+
+  /**
+   * This method does nothing as a Separator is just blank space.
+   *
+   * @param g The Graphics object to paint with
+   * @param c The JComponent to paint.
+   */
+  public void paint(Graphics g, JComponent c)
+  {
+    // Do nothing.
+  }
+
+  /**
+   * This method returns the preferred size of the  JComponent.
+   *
+   * @param c The JComponent to measure.
+   *
+   * @return The preferred size.
+   */
+  public Dimension getPreferredSize(JComponent c)
+  {
+    return size;
+  }
+
+  /**
+   * This method returns the minimum size of the JComponent.
+   *
+   * @param c The JComponent to measure.
+   *
+   * @return The minimum size.
+   */
+  public Dimension getMinimumSize(JComponent c)
+  {
+    return size;
+  }
+
+  /**
+   * This method returns the maximum size of the JComponent.
+   *
+   * @param c The JComponent to measure.
+   *
+   * @return The maximum size.
+   */
+  public Dimension getMaximumSize(JComponent c)
+  {
+    return size;
+  }
+}

Added: llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/BasicToolBarUI.java
URL: http://llvm.org/viewvc/llvm-project/llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/BasicToolBarUI.java?rev=43913&view=auto

==============================================================================
--- llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/BasicToolBarUI.java (added)
+++ llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/BasicToolBarUI.java Thu Nov  8 16:56:19 2007
@@ -0,0 +1,1608 @@
+/* BasicToolBarUI.java --
+   Copyright (C) 2004, 2005, 2006  Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package javax.swing.plaf.basic;
+
+import java.awt.BorderLayout;
+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.Rectangle;
+import java.awt.Window;
+import java.awt.event.ActionEvent;
+import java.awt.event.ContainerEvent;
+import java.awt.event.ContainerListener;
+import java.awt.event.FocusEvent;
+import java.awt.event.FocusListener;
+import java.awt.event.MouseEvent;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.awt.event.WindowListener;
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+import java.util.Hashtable;
+
+import javax.swing.AbstractAction;
+import javax.swing.AbstractButton;
+import javax.swing.Action;
+import javax.swing.ActionMap;
+import javax.swing.InputMap;
+import javax.swing.JButton;
+import javax.swing.JComponent;
+import javax.swing.JDialog;
+import javax.swing.JFrame;
+import javax.swing.JToolBar;
+import javax.swing.KeyStroke;
+import javax.swing.LookAndFeel;
+import javax.swing.RootPaneContainer;
+import javax.swing.SwingConstants;
+import javax.swing.SwingUtilities;
+import javax.swing.UIManager;
+import javax.swing.border.Border;
+import javax.swing.border.CompoundBorder;
+import javax.swing.event.MouseInputListener;
+import javax.swing.plaf.ActionMapUIResource;
+import javax.swing.plaf.ComponentUI;
+import javax.swing.plaf.ToolBarUI;
+import javax.swing.plaf.UIResource;
+import javax.swing.plaf.basic.BasicBorders.ButtonBorder;
+
+/**
+ * This is the Basic Look and Feel UI class for JToolBar.
+ */
+public class BasicToolBarUI extends ToolBarUI implements SwingConstants
+{
+
+  /**
+   * Implements the keyboard actions for JToolBar.
+   */
+  static class ToolBarAction
+    extends AbstractAction
+  {
+    /**
+     * Performs the action.
+     */
+    public void actionPerformed(ActionEvent event)
+    {
+      Object cmd = getValue("__command__");
+      JToolBar toolBar = (JToolBar) event.getSource();
+      BasicToolBarUI ui = (BasicToolBarUI) toolBar.getUI();
+
+      if (cmd.equals("navigateRight"))
+        ui.navigateFocusedComp(EAST);
+      else if (cmd.equals("navigateLeft"))
+          ui.navigateFocusedComp(WEST);
+      else if (cmd.equals("navigateUp"))
+          ui.navigateFocusedComp(NORTH);
+      else if (cmd.equals("navigateDown"))
+        ui.navigateFocusedComp(SOUTH);
+      else
+        assert false : "Shouldn't reach here";
+    }
+  }
+
+  /** Static owner of all DragWindows.
+   * This is package-private to avoid an accessor method.  */
+  static JFrame owner = new JFrame();
+
+  /** The border used when the JToolBar is in nonrollover mode. */
+  private static Border nonRolloverBorder;
+
+  /** The border used when the JToolBar is in rollover mode. */
+  private static Border rolloverBorder;
+
+  /** The last known BorderLayout constraint before floating. */
+  protected String constraintBeforeFloating;
+
+  /** The last known orientation of the JToolBar before floating.
+   * This is package-private to avoid an accessor method.  */
+  int lastGoodOrientation;
+
+  /** The color of the border when it is dockable. */
+  protected Color dockingBorderColor;
+
+  /** The background color of the JToolBar when it is dockable. */
+  protected Color dockingColor;
+
+  /** The docking listener responsible for mouse events on the JToolBar. */
+  protected MouseInputListener dockingListener;
+
+  /** The window used for dragging the JToolBar. */
+  protected BasicToolBarUI.DragWindow dragWindow;
+
+  /** The color of the border when it is not dockable. */
+  protected Color floatingBorderColor;
+
+  /** The background color of the JToolBar when it is not dockable. */
+  protected Color floatingColor;
+
+  /** The index of the focused component. */
+  protected int focusedCompIndex;
+
+  /** The PropertyChangeListener for the JToolBar. */
+  protected PropertyChangeListener propertyListener;
+
+  /** The JToolBar this UI delegate is responsible for. */
+  protected JToolBar toolBar;
+
+  /** The Container listener for the JToolBar. */
+  protected ContainerListener toolBarContListener;
+
+  /** The Focus listener for the JToolBar. */
+  protected FocusListener toolBarFocusListener;
+
+  /**
+   * @deprecated since JDK1.3.
+   */
+  protected KeyStroke leftKey;
+
+  /**
+   * @deprecated since JDK1.3.
+   */
+  protected KeyStroke rightKey;
+
+  /**
+   * @deprecated since JDK1.3.
+   */
+  protected KeyStroke upKey;
+
+  /**
+   * @deprecated since JDK1.3.
+   */
+  protected KeyStroke downKey;
+
+  /**
+   * The floating window that is responsible for holding the JToolBar when it
+   * is dragged outside of its original parent.
+   */
+  private transient Window floatFrame;
+
+  /** The original parent of the JToolBar.
+   * This is package-private to avoid an accessor method.  */
+  transient Container origParent;
+
+  /** A hashtable of components and their original borders.
+   * This is package-private to avoid an accessor method.  */
+  transient Hashtable borders;
+
+  /** A window listener for the floatable frame. */
+  private transient WindowListener windowListener;
+
+  /** A set of cached bounds of the JToolBar.
+   * This is package-private to avoid an accessor method.  */
+  transient Dimension cachedBounds;
+
+  /** The cached orientation of the JToolBar.
+   * This is package-private to avoid an accessor method.  */
+  transient int cachedOrientation;
+
+  /**
+   * This method creates a new <code>BasicToolBarUI</code> object for the given JToolBar.
+   */
+  public BasicToolBarUI()
+  {
+    // Do nothing here.
+  }
+
+  /**
+   * This method returns whether the JToolBar can dock at the given position.
+   *
+   * @param c The component to try to dock in.
+   * @param p The position of the mouse cursor relative to the given
+   *        component.
+   *
+   * @return Whether the JToolBar can dock.
+   */
+  public boolean canDock(Component c, Point p)
+  {
+    return areaOfClick(c, p) != -1;
+  }
+
+  /**
+   * This helper method returns the position of the JToolBar if it can dock.
+   *
+   * @param c The component to try to dock in.
+   * @param p The position of the mouse cursor relative to the given
+   *        component.
+   *
+   * @return One of the SwingConstants directions or -1 if the JToolBar can't
+   *         dock.
+   */
+  private int areaOfClick(Component c, Point p)
+  {
+    // Has to dock in immediate parent, not eventual root container.
+    Rectangle pBounds = c.getBounds();
+
+    // XXX: In Sun's implementation, the space the toolbar has to dock is dependent on the size it had last.
+    Dimension d = toolBar.getSize();
+    int limit = Math.min(d.width, d.height);
+
+    // The order of checking is 1. top 2. bottom 3. left 4. right
+    if (! pBounds.contains(p))
+      return -1;
+
+    if (p.y < limit)
+      return SwingConstants.NORTH;
+
+    if (p.y > (pBounds.height - limit))
+      return SwingConstants.SOUTH;
+
+    if (p.x < limit)
+      return SwingConstants.WEST;
+
+    if (p.x > (pBounds.width - limit))
+      return SwingConstants.EAST;
+
+    return -1;
+  }
+
+  /**
+   * This method creates a new DockingListener for the JToolBar.
+   *
+   * @return A new DockingListener for the JToolBar.
+   */
+  protected MouseInputListener createDockingListener()
+  {
+    return new DockingListener(toolBar);
+  }
+
+  /**
+   * This method creates a new DragWindow for the given JToolBar.
+   *
+   * @param toolbar The JToolBar to create a DragWindow for.
+   *
+   * @return A new DragWindow.
+   */
+  protected BasicToolBarUI.DragWindow createDragWindow(JToolBar toolbar)
+  {
+    return new DragWindow();
+  }
+
+  /**
+   * This method creates a new floating frame for the JToolBar. By default,
+   * this UI uses createFloatingWindow instead. This method of creating a
+   * floating frame is deprecated.
+   *
+   * @param toolbar The JToolBar to create a floating frame for.
+   *
+   * @return A new floating frame.
+   */
+  protected JFrame createFloatingFrame(JToolBar toolbar)
+  {
+    // FIXME: Though deprecated, this should still work.
+    return null;
+  }
+
+  /**
+   * This method creates a new floating window for the JToolBar. This is the
+   * method used by default to create a floating container for the JToolBar.
+   *
+   * @param toolbar The JToolBar to create a floating window for.
+   *
+   * @return A new floating window.
+   */
+  protected RootPaneContainer createFloatingWindow(JToolBar toolbar)
+  {
+    // This one is used by default though.
+    return new ToolBarDialog();
+  }
+
+  /**
+   * This method creates a new WindowListener for the JToolBar.
+   *
+   * @return A new WindowListener.
+   */
+  protected WindowListener createFrameListener()
+  {
+    return new FrameListener();
+  }
+
+  /**
+   * This method creates a new nonRolloverBorder for JButtons when the
+   * JToolBar's rollover property is set to false.
+   *
+   * @return A new NonRolloverBorder.
+   */
+  protected Border createNonRolloverBorder()
+  {
+    Border b = UIManager.getBorder("ToolBar.nonrolloverBorder");
+    
+    if (b == null)
+      {
+        b = new CompoundBorder(
+            new ButtonBorder(UIManager.getColor("Button.shadow"),
+                             UIManager.getColor("Button.darkShadow"),
+                             UIManager.getColor("Button.light"),
+                             UIManager.getColor("Button.highlight")),
+            BasicBorders.getMarginBorder());
+      }
+    
+    return b;  }
+
+  /**
+   * This method creates a new PropertyChangeListener for the JToolBar.
+   *
+   * @return A new PropertyChangeListener.
+   */
+  protected PropertyChangeListener createPropertyListener()
+  {
+    return new PropertyListener();
+  }
+
+  /**
+   * This method creates a new rollover border for JButtons when the
+   * JToolBar's rollover property is set to true.
+   *
+   * @return A new rollover border.
+   */
+  protected Border createRolloverBorder()
+  {
+    Border b = UIManager.getBorder("ToolBar.rolloverBorder");
+    
+    if (b == null)
+      {
+        b = new CompoundBorder(
+            new ButtonBorder(UIManager.getColor("Button.shadow"),
+                             UIManager.getColor("Button.darkShadow"),
+                             UIManager.getColor("Button.light"),
+                             UIManager.getColor("Button.highlight")),
+            BasicBorders.getMarginBorder());
+      }
+    
+    return b;
+  }
+
+  /**
+   * This method creates a new Container listener for the JToolBar.
+   *
+   * @return A new Container listener.
+   */
+  protected ContainerListener createToolBarContListener()
+  {
+    return new ToolBarContListener();
+  }
+
+  /**
+   * This method creates a new FocusListener for the JToolBar.
+   *
+   * @return A new FocusListener for the JToolBar.
+   */
+  protected FocusListener createToolBarFocusListener()
+  {
+    return new ToolBarFocusListener();
+  }
+
+  /**
+   * This method creates a new UI delegate for the given JComponent.
+   *
+   * @param c The JComponent to create a UI delegate for.
+   *
+   * @return A new UI delegate.
+   */
+  public static ComponentUI createUI(JComponent c)
+  {
+    return new BasicToolBarUI();
+  }
+
+  /**
+   * This method is called to drag the DragWindow around when the JToolBar is
+   * being dragged around.
+   *
+   * @param position The mouse cursor coordinates relative to the JToolBar.
+   * @param origin The screen position of the JToolBar.
+   */
+  protected void dragTo(Point position, Point origin)
+  {
+    int loc = areaOfClick(origParent,
+                          SwingUtilities.convertPoint(toolBar, position,
+                                                      origParent));
+
+    if (loc != -1)
+      {
+	dragWindow.setBorderColor(dockingBorderColor);
+	dragWindow.setBackground(dockingColor);
+      }
+    else
+      {
+	dragWindow.setBorderColor(floatingBorderColor);
+	dragWindow.setBackground(floatingColor);
+      }
+
+    int w = 0;
+    int h = 0;
+
+    boolean tmp = (loc == SwingConstants.NORTH)
+                  || (loc == SwingConstants.SOUTH) || (loc == -1);
+
+    cachedOrientation = toolBar.getOrientation();
+    cachedBounds = toolBar.getSize();
+    if (((cachedOrientation == SwingConstants.HORIZONTAL) && tmp)
+        || ((cachedOrientation == VERTICAL) && ! tmp))
+      {
+	w = cachedBounds.width;
+	h = cachedBounds.height;
+      }
+    else
+      {
+	w = cachedBounds.height;
+	h = cachedBounds.width;
+      }
+
+    Point p = dragWindow.getOffset();
+    Insets insets = toolBar.getInsets();
+
+    dragWindow.setBounds((origin.x + position.x) - p.x
+                         - ((insets.left + insets.right) / 2),
+                         (origin.y + position.y) - p.y
+                         - ((insets.top + insets.bottom) / 2), w, h);
+
+    if (! dragWindow.isVisible())
+      dragWindow.show();
+  }
+
+  /**
+   * This method is used at the end of a drag session to place the frame in
+   * either its original parent as a docked JToolBar or in its floating
+   * frame.
+   *
+   * @param position The position of the mouse cursor relative to the
+   *        JToolBar.
+   * @param origin The screen position of the JToolBar before the drag session
+   *        started.
+   */
+  protected void floatAt(Point position, Point origin)
+  {
+    Point p = new Point(position);
+    int aoc = areaOfClick(origParent,
+                          SwingUtilities.convertPoint(toolBar, p, origParent));
+
+    Container oldParent = toolBar.getParent();
+
+    oldParent.remove(toolBar);
+    oldParent.doLayout();
+    oldParent.repaint();
+
+    Container newParent;
+
+    if (aoc == -1)
+      newParent = ((RootPaneContainer) floatFrame).getContentPane();
+    else
+      {
+	floatFrame.hide();
+	newParent = origParent;
+      }
+
+    String constraint;
+    switch (aoc)
+      {
+      case SwingConstants.EAST:
+	constraint = BorderLayout.EAST;
+	break;
+      case SwingConstants.NORTH:
+	constraint = BorderLayout.NORTH;
+	break;
+      case SwingConstants.SOUTH:
+	constraint = BorderLayout.SOUTH;
+	break;
+      case SwingConstants.WEST:
+	constraint = BorderLayout.WEST;
+	break;
+      default:
+	constraint = BorderLayout.CENTER;
+	break;
+      }
+
+    int newOrientation = SwingConstants.HORIZONTAL;
+    if ((aoc != -1)
+        && ((aoc == SwingConstants.EAST) || (aoc == SwingConstants.WEST)))
+      newOrientation = SwingConstants.VERTICAL;
+
+    if (aoc != -1)
+      {
+	constraintBeforeFloating = constraint;
+	lastGoodOrientation = newOrientation;
+      }
+
+    newParent.add(toolBar, constraint);
+
+    setFloating(aoc == -1, null);
+    toolBar.setOrientation(newOrientation);
+
+    Insets insets = floatFrame.getInsets();
+    Dimension dims = toolBar.getPreferredSize();
+    p = dragWindow.getOffset();
+    setFloatingLocation((position.x + origin.x) - p.x
+                        - ((insets.left + insets.right) / 2),
+                        (position.y + origin.y) - p.y
+                        - ((insets.top + insets.bottom) / 2));
+
+    if (aoc == -1)
+      {
+	floatFrame.pack();
+	floatFrame.setSize(dims.width + insets.left + insets.right,
+	                   dims.height + insets.top + insets.bottom);
+	floatFrame.show();
+      }
+
+    newParent.invalidate();
+    newParent.validate();
+    newParent.repaint();
+  }
+
+  /**
+   * This method returns the docking color.
+   *
+   * @return The docking color.
+   */
+  public Color getDockingColor()
+  {
+    return dockingColor;
+  }
+
+  /**
+   * This method returns the Color which is displayed when over a floating
+   * area.
+   *
+   * @return The color which is displayed when over a floating area.
+   */
+  public Color getFloatingColor()
+  {
+    return floatingColor;
+  }
+
+  /**
+   * This method returns the maximum size of the given JComponent for this UI.
+   *
+   * @param c The JComponent to find the maximum size for.
+   *
+   * @return The maximum size for this UI.
+   */
+  public Dimension getMaximumSize(JComponent c)
+  {
+    return getPreferredSize(c);
+  }
+
+  /**
+   * This method returns the minimum size of the given JComponent for this UI.
+   *
+   * @param c The JComponent to find a minimum size for.
+   *
+   * @return The minimum size for this UI.
+   */
+  public Dimension getMinimumSize(JComponent c)
+  {
+    return getPreferredSize(c);
+  }
+
+  /**
+   * This method installs the needed components for the JToolBar.
+   */
+  protected void installComponents()
+  {
+    floatFrame = (Window) createFloatingWindow(toolBar);
+
+    dragWindow = createDragWindow(toolBar);
+
+    nonRolloverBorder = createNonRolloverBorder();
+    rolloverBorder = createRolloverBorder();
+
+    borders = new Hashtable();
+    setRolloverBorders(toolBar.isRollover());
+
+    fillHashtable();
+  }
+
+  /**
+   * This method installs the defaults as specified by the look and feel.
+   */
+  protected void installDefaults()
+  {
+    LookAndFeel.installBorder(toolBar, "ToolBar.border");
+    LookAndFeel.installColorsAndFont(toolBar, "ToolBar.background",
+                                     "ToolBar.foreground", "ToolBar.font");
+
+    dockingBorderColor = UIManager.getColor("ToolBar.dockingForeground");
+    dockingColor = UIManager.getColor("ToolBar.dockingBackground");
+
+    floatingBorderColor = UIManager.getColor("ToolBar.floatingForeground");
+    floatingColor = UIManager.getColor("ToolBar.floatingBackground");
+  }
+
+  /**
+   * This method installs the keyboard actions for the JToolBar as specified
+   * by the look and feel.
+   */
+  protected void installKeyboardActions()
+  {
+    // Install the input map.
+    InputMap inputMap =
+      (InputMap) SharedUIDefaults.get("ToolBar.ancestorInputMap");
+    SwingUtilities.replaceUIInputMap(toolBar,
+                                 JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT,
+                                 inputMap);
+
+    // FIXME: The JDK uses a LazyActionMap for parentActionMap
+    SwingUtilities.replaceUIActionMap(toolBar, getActionMap());
+  }
+
+  /**
+   * Fetches the action map from  the UI defaults, or create a new one
+   * if the action map hasn't been initialized.
+   *
+   * @return the action map
+   */
+  private ActionMap getActionMap()
+  {
+    ActionMap am = (ActionMap) UIManager.get("ToolBar.actionMap");
+    if (am == null)
+      {
+        am = createDefaultActions();
+        UIManager.getLookAndFeelDefaults().put("ToolBar.actionMap", am);
+      }
+    return am;
+  }
+
+  private ActionMap createDefaultActions()
+  {
+    ActionMapUIResource am = new ActionMapUIResource();
+    Action action = new ToolBarAction();
+
+    am.put("navigateLeft", action);
+    am.put("navigateRight", action);
+    am.put("navigateUp", action);
+    am.put("navigateDown", action);
+
+    return am;
+  }
+
+  /**
+   * This method installs listeners for the JToolBar.
+   */
+  protected void installListeners()
+  {
+    dockingListener = createDockingListener();
+    toolBar.addMouseListener(dockingListener);
+    toolBar.addMouseMotionListener(dockingListener);
+
+    propertyListener = createPropertyListener();
+    toolBar.addPropertyChangeListener(propertyListener);
+
+    toolBarContListener = createToolBarContListener();
+    toolBar.addContainerListener(toolBarContListener);
+
+    windowListener = createFrameListener();
+    floatFrame.addWindowListener(windowListener);
+
+    toolBarFocusListener = createToolBarFocusListener();
+    if (toolBarFocusListener != null)
+      {
+        int count = toolBar.getComponentCount();
+        for (int i = 0; i < count; i++)
+          toolBar.getComponent(i).addFocusListener(toolBarFocusListener);
+      }
+  }
+
+  /**
+   * This method installs non rollover borders for each component inside the
+   * given JComponent.
+   *
+   * @param c The JComponent whose children need to have non rollover borders
+   *        installed.
+   */
+  protected void installNonRolloverBorders(JComponent c)
+  {
+    Component[] components = toolBar.getComponents();
+
+    for (int i = 0; i < components.length; i++)
+      setBorderToNonRollover(components[i]);
+  }
+
+  /**
+   * This method installs normal (or their original) borders for each
+   * component inside the given JComponent.
+   *
+   * @param c The JComponent whose children need to have their original
+   *        borders installed.
+   */
+  protected void installNormalBorders(JComponent c)
+  {
+    Component[] components = toolBar.getComponents();
+
+    for (int i = 0; i < components.length; i++)
+      setBorderToNormal(components[i]);
+  }
+
+  /**
+   * This method install rollover borders for each component inside the given
+   * JComponent.
+   *
+   * @param c The JComponent whose children need to have rollover borders
+   *        installed.
+   */
+  protected void installRolloverBorders(JComponent c)
+  {
+    Component[] components = toolBar.getComponents();
+
+    for (int i = 0; i < components.length; i++)
+      setBorderToRollover(components[i]);
+  }
+
+  /**
+   * This method fills the borders hashtable with a list of components that
+   * are JButtons and their borders.
+   */
+  private void fillHashtable()
+  {
+    Component[] c = toolBar.getComponents();
+
+    for (int i = 0; i < c.length; i++)
+      {
+	if (c[i] instanceof JButton)
+	  {
+	    // Don't really care about anything other than JButtons
+	    JButton b = (JButton) c[i];
+
+	    if (b.getBorder() != null)
+	      borders.put(b, b.getBorder());
+	  }
+      }
+  }
+
+  /**
+   * This method installs the UI for the given JComponent.
+   *
+   * @param c The JComponent to install a UI for.
+   */
+  public void installUI(JComponent c)
+  {
+    super.installUI(c);
+
+    if (c instanceof JToolBar)
+      {
+	toolBar = (JToolBar) c;
+    installDefaults();
+    installComponents();
+	installListeners();
+	installKeyboardActions();
+      }
+  }
+
+  /**
+   * This method returns whether the JToolBar is floating.
+   *
+   * @return Whether the JToolBar is floating.
+   */
+  public boolean isFloating()
+  {
+    return floatFrame.isVisible();
+  }
+
+  /**
+   * This method returns whether rollover borders have been set.
+   *
+   * @return Whether rollover borders have been set.
+   */
+  public boolean isRolloverBorders()
+  {
+    return toolBar.isRollover();
+  }
+
+  /**
+   * This method navigates in the given direction giving focus to the next
+   * component in the given direction.
+   *
+   * @param direction The direction to give focus to.
+   */
+  protected void navigateFocusedComp(int direction)
+  {
+    int count = toolBar.getComponentCount();
+    switch (direction)
+    {
+      case EAST:
+      case SOUTH:
+        if (focusedCompIndex >= 0 && focusedCompIndex < count)
+          {
+            int i = focusedCompIndex + 1;
+            boolean focusRequested = false;
+            // Find component to focus and request focus on it.
+            while (i != focusedCompIndex && ! focusRequested)
+              {
+                if (i >= count)
+                  i = 0;
+                Component comp = toolBar.getComponentAtIndex(i++);
+                if (comp != null && comp.isFocusable()
+                    && comp.isEnabled())
+                  {
+                    comp.requestFocus();
+                    focusRequested = true;
+                  }
+              }
+          }
+        break;
+      case WEST:
+      case NORTH:
+        if (focusedCompIndex >= 0 && focusedCompIndex < count)
+          {
+            int i = focusedCompIndex - 1;
+            boolean focusRequested = false;
+            // Find component to focus and request focus on it.
+            while (i != focusedCompIndex && ! focusRequested)
+              {
+                if (i < 0)
+                  i = count - 1;
+                Component comp = toolBar.getComponentAtIndex(i--);
+                if (comp != null && comp.isFocusable()
+                    && comp.isEnabled())
+                  {
+                    comp.requestFocus();
+                    focusRequested = true;
+                  }
+              }
+          }
+        break;
+      default:
+        break;
+    }
+  }
+
+  /**
+   * This method sets the border of the given component to a non rollover
+   * border.
+   *
+   * @param c The Component whose border needs to be set.
+   */
+  protected void setBorderToNonRollover(Component c)
+  {
+    if (c instanceof AbstractButton)
+      {
+	AbstractButton b = (AbstractButton) c;
+	b.setRolloverEnabled(false);
+
+        // Save old border in hashtable.
+        borders.put(b, b.getBorder());
+        
+	b.setBorder(nonRolloverBorder);
+      }
+  }
+
+  /**
+   * This method sets the border of the given component to its original value.
+   *
+   * @param c The Component whose border needs to be set.
+   */
+  protected void setBorderToNormal(Component c)
+  {
+    if (c instanceof AbstractButton)
+      {
+        AbstractButton b = (AbstractButton) c;
+        b.setRolloverEnabled(true);
+        b.setBorder((Border) borders.remove(b));
+      }
+  }
+
+  /**
+   * This method sets the border of the given component to a rollover border.
+   *
+   * @param c The Component whose border needs to be set.
+   */
+  protected void setBorderToRollover(Component c)
+  {
+    if (c instanceof AbstractButton)
+      {
+        AbstractButton b = (AbstractButton) c;
+        b.setRolloverEnabled(false);
+        
+        // Save old border in hashtable.
+        borders.put(b, b.getBorder());
+        
+        b.setBorder(rolloverBorder);
+      }
+  }
+
+  /**
+   * This method sets the docking color.
+   *
+   * @param c The docking color.
+   */
+  public void setDockingColor(Color c)
+  {
+    dockingColor = c;
+  }
+
+  /**
+   * This method sets the floating property for the JToolBar.
+   *
+   * @param b Whether the JToolBar is floating.
+   * @param p FIXME
+   */
+  public void setFloating(boolean b, Point p)
+  {
+    // FIXME: use p for something. It's not location
+    // since we already have setFloatingLocation.
+    floatFrame.setVisible(b);
+  }
+
+  /**
+   * This method sets the color displayed when the JToolBar is not in a
+   * dockable area.
+   *
+   * @param c The floating color.
+   */
+  public void setFloatingColor(Color c)
+  {
+    floatingColor = c;
+  }
+
+  /**
+   * This method sets the floating location of the JToolBar.
+   *
+   * @param x The x coordinate for the floating frame.
+   * @param y The y coordinate for the floating frame.
+   */
+  public void setFloatingLocation(int x, int y)
+  {
+    // x,y are the coordinates of the new JFrame created to store the toolbar
+    // XXX: The floating location is bogus is not floating.
+    floatFrame.setLocation(x, y);
+    floatFrame.invalidate();
+    floatFrame.validate();
+    floatFrame.repaint();
+  }
+
+  /**
+   * This is a convenience method for changing the orientation of the
+   * JToolBar.
+   *
+   * @param orientation The new orientation.
+   */
+  public void setOrientation(int orientation)
+  {
+    toolBar.setOrientation(orientation);
+  }
+
+  /**
+   * This method changes the child components to have rollover borders if the
+   * given parameter is true. Otherwise, the components are set to have non
+   * rollover borders.
+   *
+   * @param rollover Whether the children will have rollover borders.
+   */
+  public void setRolloverBorders(boolean rollover)
+  {
+    if (rollover)
+      installRolloverBorders(toolBar);
+    else
+      installNonRolloverBorders(toolBar);
+  }
+
+  /**
+   * This method uninstall UI installed components from the JToolBar.
+   */
+  protected void uninstallComponents()
+  {
+    installNormalBorders(toolBar);
+    borders = null;
+    cachedBounds = null;
+
+    floatFrame = null;
+    dragWindow = null;
+  }
+
+  /**
+   * This method removes the defaults installed by the Look and Feel.
+   */
+  protected void uninstallDefaults()
+  {
+    toolBar.setBackground(null);
+    toolBar.setForeground(null);
+    toolBar.setFont(null);
+
+    dockingBorderColor = null;
+    dockingColor = null;
+    floatingBorderColor = null;
+    floatingColor = null;
+  }
+
+  /**
+   * This method uninstalls keyboard actions installed by the UI.
+   */
+  protected void uninstallKeyboardActions()
+  {
+    SwingUtilities.replaceUIInputMap(toolBar, JComponent.
+                                     WHEN_ANCESTOR_OF_FOCUSED_COMPONENT, null);
+    SwingUtilities.replaceUIActionMap(toolBar, null);
+  }
+
+  /**
+   * This method uninstalls listeners installed by the UI.
+   */
+  protected void uninstallListeners()
+  {
+    if (toolBarFocusListener != null)
+      {
+        int count = toolBar.getComponentCount();
+        for (int i = 0; i < count; i++)
+          toolBar.getComponent(i).removeFocusListener(toolBarFocusListener);
+        toolBarFocusListener = null;
+      }
+
+    floatFrame.removeWindowListener(windowListener);
+    windowListener = null;
+
+    toolBar.removeContainerListener(toolBarContListener);
+    toolBarContListener = null;
+
+    toolBar.removeMouseMotionListener(dockingListener);
+    toolBar.removeMouseListener(dockingListener);
+    dockingListener = null;
+  }
+
+  /**
+   * This method uninstalls the UI.
+   *
+   * @param c The JComponent that is having this UI removed.
+   */
+  public void uninstallUI(JComponent c)
+  {
+    uninstallKeyboardActions();
+    uninstallListeners();
+    uninstallComponents();
+    uninstallDefaults();
+    toolBar = null;
+  }
+
+  /**
+   * This is the MouseHandler class that allows the user to drag the JToolBar
+   * in and out of the parent and dock it if it can.
+   */
+  public class DockingListener implements MouseInputListener
+  {
+    /** Whether the JToolBar is being dragged. */
+    protected boolean isDragging;
+
+    /**
+     * The origin point. This point is saved from the beginning press and is
+     * used until the end of the drag session.
+     */
+    protected Point origin;
+
+    /** The JToolBar being dragged. */
+    protected JToolBar toolBar;
+
+    /**
+     * Creates a new DockingListener object.
+     *
+     * @param t The JToolBar this DockingListener is being used for.
+     */
+    public DockingListener(JToolBar t)
+    {
+      toolBar = t;
+    }
+
+    /**
+     * This method is called when the mouse is clicked.
+     *
+     * @param e The MouseEvent.
+     */
+    public void mouseClicked(MouseEvent e)
+    {
+      // Nothing to do here.
+    }
+
+    /**
+     * This method is called when the mouse is dragged. It delegates the drag
+     * painting to the dragTo method.
+     *
+     * @param e The MouseEvent.
+     */
+    public void mouseDragged(MouseEvent e)
+    {
+      if (isDragging)
+	dragTo(e.getPoint(), origin);
+    }
+
+    /**
+     * This method is called when the mouse enters the JToolBar.
+     *
+     * @param e The MouseEvent.
+     */
+    public void mouseEntered(MouseEvent e)
+    {
+      // Nothing to do here.
+    }
+
+    /**
+     * This method is called when the mouse exits the JToolBar.
+     *
+     * @param e The MouseEvent.
+     */
+    public void mouseExited(MouseEvent e)
+    {
+      // Nothing to do here.
+    }
+
+    /**
+     * This method is called when the mouse is moved in the JToolBar.
+     *
+     * @param e The MouseEvent.
+     */
+    public void mouseMoved(MouseEvent e)
+    {
+      // Nothing to do here.
+    }
+
+    /**
+     * This method is called when the mouse is pressed in the JToolBar. If the
+     * press doesn't occur in a place where it causes the JToolBar to be
+     * dragged, it returns. Otherwise, it starts a drag session.
+     *
+     * @param e The MouseEvent.
+     */
+    public void mousePressed(MouseEvent e)
+    {
+      if (! toolBar.isFloatable())
+	return;
+
+      Point ssd = e.getPoint();
+      Insets insets = toolBar.getInsets();
+
+      // Verify that this click occurs in the top inset.
+      if (toolBar.getOrientation() == SwingConstants.HORIZONTAL)
+        {
+	  if (e.getX() > insets.left)
+	    return;
+        }
+      else
+        {
+	  if (e.getY() > insets.top)
+	    return;
+        }
+
+      origin = new Point(0, 0);
+      if (toolBar.isShowing())
+        SwingUtilities.convertPointToScreen(ssd, toolBar);
+
+      if (! (SwingUtilities.getAncestorOfClass(Window.class, toolBar) instanceof UIResource))
+	// Need to know who keeps the toolBar if it gets dragged back into it.
+	origParent = toolBar.getParent();
+      
+      if (toolBar.isShowing())
+        SwingUtilities.convertPointToScreen(origin, toolBar);
+
+      isDragging = true;
+
+      if (dragWindow != null)
+	dragWindow.setOffset(new Point(cachedBounds.width / 2, 
+            cachedBounds.height / 2));
+
+      dragTo(e.getPoint(), origin);
+    }
+
+    /**
+     * This method is called when the mouse is released from the JToolBar.
+     *
+     * @param e The MouseEvent.
+     */
+    public void mouseReleased(MouseEvent e)
+    {
+      if (! isDragging || ! toolBar.isFloatable())
+	return;
+
+      isDragging = false;
+      floatAt(e.getPoint(), origin);
+      dragWindow.hide();
+    }
+  }
+
+  /**
+   * This is the window that appears when the JToolBar is being dragged
+   * around.
+   */
+  protected class DragWindow extends Window
+  {
+    /**
+     * The current border color. It changes depending on whether the JToolBar
+     * is over a place that allows it to dock.
+     */
+    private Color borderColor;
+
+    /** The between the mouse and the top left corner of the window. */
+    private Point offset;
+
+    /**
+     * Creates a new DragWindow object.
+     * This is package-private to avoid an accessor method.
+     */
+    DragWindow()
+    {
+      super(owner);
+    }
+
+    /**
+     * The color that the border should be.
+     *
+     * @return The border color.
+     */
+    public Color getBorderColor()
+    {
+      if (borderColor == null)
+	return Color.BLACK;
+
+      return borderColor;
+    }
+
+    /**
+     * This method returns the insets for the DragWindow.
+     *
+     * @return The insets for the DragWindow.
+     */
+    public Insets getInsets()
+    {
+      // This window has no decorations, so insets are empty.
+      return new Insets(0, 0, 0, 0);
+    }
+
+    /**
+     * This method returns the mouse offset from the top left corner of the
+     * DragWindow.
+     *
+     * @return The mouse offset.
+     */
+    public Point getOffset()
+    {
+      return offset;
+    }
+
+    /**
+     * This method paints the DragWindow.
+     *
+     * @param g The Graphics object to paint with.
+     */
+    public void paint(Graphics g)
+    {
+      //  No visiting children necessary.
+      Color saved = g.getColor();
+      Rectangle b = getBounds();
+
+      g.setColor(getBorderColor());
+      g.drawRect(0, 0, b.width - 1, b.height - 1);
+
+      g.setColor(saved);
+    }
+
+    /**
+     * This method changes the border color.
+     *
+     * @param c The new border color.
+     */
+    public void setBorderColor(Color c)
+    {
+      borderColor = c;
+    }
+
+    /**
+     * This method changes the mouse offset.
+     *
+     * @param p The new mouse offset.
+     */
+    public void setOffset(Point p)
+    {
+      offset = p;
+    }
+
+    /**
+     * Sets the orientation of the toolbar and the
+     * drag window.
+     *
+     * @param o - the new orientation of the toolbar and drag
+     * window.
+     */
+    public void setOrientation(int o)
+    {
+      toolBar.setOrientation(o);
+      if (dragWindow != null) 
+        dragWindow.setOrientation(o);
+    }
+  }
+
+  /**
+   * This helper class listens for Window events from the floatable window and
+   * if it is closed, returns the JToolBar to the last known good location.
+   */
+  protected class FrameListener extends WindowAdapter
+  {
+    /**
+     * This method is called when the floating window is closed.
+     *
+     * @param e The WindowEvent.
+     */
+    public void windowClosing(WindowEvent e)
+    {
+      Container parent = toolBar.getParent();
+      parent.remove(toolBar);
+
+      if (origParent != null)
+        {
+	  origParent.add(toolBar,
+	                 (constraintBeforeFloating != null)
+	                 ? constraintBeforeFloating : BorderLayout.NORTH);
+	  toolBar.setOrientation(lastGoodOrientation);
+        }
+
+      origParent.invalidate();
+      origParent.validate();
+      origParent.repaint();
+    }
+  }
+
+  /**
+   * This helper class listens for PropertyChangeEvents from the JToolBar.
+   */
+  protected class PropertyListener implements PropertyChangeListener
+  {
+    /**
+     * This method is called when a property from the JToolBar is changed.
+     *
+     * @param e The PropertyChangeEvent.
+     */
+    public void propertyChange(PropertyChangeEvent e)
+    {
+      // FIXME: need name properties so can change floatFrame title.
+      if (e.getPropertyName().equals("rollover") && toolBar != null)
+        setRolloverBorders(toolBar.isRollover());
+    }
+  }
+
+  /**
+   * This helper class listens for components added to and removed from the
+   * JToolBar.
+   */
+  protected class ToolBarContListener implements ContainerListener
+  {
+    /**
+     * This method is responsible for setting rollover or non rollover for new
+     * buttons added to the JToolBar.
+     *
+     * @param e The ContainerEvent.
+     */
+    public void componentAdded(ContainerEvent e)
+    {
+      if (e.getChild() instanceof JButton)
+        {
+	  JButton b = (JButton) e.getChild();
+
+	  if (b.getBorder() != null)
+	    borders.put(b, b.getBorder());
+        }
+
+      if (isRolloverBorders())
+	setBorderToRollover(e.getChild());
+      else
+	setBorderToNonRollover(e.getChild());
+
+      cachedBounds = toolBar.getPreferredSize();
+      cachedOrientation = toolBar.getOrientation();
+
+      Component c = e.getChild();
+      if (toolBarFocusListener != null)
+        c.addFocusListener(toolBarFocusListener);
+    }
+
+    /**
+     * This method is responsible for giving the child components their
+     * original borders when they are removed.
+     *
+     * @param e The ContainerEvent.
+     */
+    public void componentRemoved(ContainerEvent e)
+    {
+      setBorderToNormal(e.getChild());
+      cachedBounds = toolBar.getPreferredSize();
+      cachedOrientation = toolBar.getOrientation();
+
+      Component c = e.getChild();
+      if (toolBarFocusListener != null)
+        c.removeFocusListener(toolBarFocusListener);
+    }
+  }
+
+  /**
+   * This is the floating window that is returned when getFloatingWindow is
+   * called.
+   */
+  private class ToolBarDialog extends JDialog implements UIResource
+  {
+    /**
+     * Creates a new ToolBarDialog object with the name given by the JToolBar.
+     */
+    public ToolBarDialog()
+    {
+      super();
+      setName((toolBar.getName() != null) ? toolBar.getName() : "");
+    }
+  }
+
+  /**
+   * DOCUMENT ME!
+   */
+  protected class ToolBarFocusListener implements FocusListener
+  {
+    /**
+     * Creates a new ToolBarFocusListener object.
+     */
+    protected ToolBarFocusListener()
+    {
+      // Nothing to do here.
+    }
+
+    /**
+     * Receives notification when the toolbar or one of it's component
+     * receives the keyboard input focus.
+     * 
+     * @param e the focus event
+     */
+    public void focusGained(FocusEvent e)
+    {
+      Component c = e.getComponent();
+      focusedCompIndex = toolBar.getComponentIndex(c);
+    }
+
+    /**
+     * Receives notification when the toolbar or one of it's component
+     * looses the keyboard input focus.
+     * 
+     * @param e the focus event
+     */
+    public void focusLost(FocusEvent e)
+    {
+      // Do nothing here.
+    }
+  }
+
+  /**
+   * This helper class acts as the border for the JToolBar.
+   */
+  private static class ToolBarBorder implements Border
+  {
+    /** The size of the larger, draggable side of the border. */
+    private static final int offset = 10;
+
+    /** The other sides. */
+    private static final int regular = 2;
+
+    /**
+     * This method returns the border insets for the JToolBar.
+     *
+     * @param c The Component to find insets for.
+     *
+     * @return The border insets.
+     */
+    public Insets getBorderInsets(Component c)
+    {
+      if (c instanceof JToolBar)
+        {
+	  JToolBar tb = (JToolBar) c;
+	  int orientation = tb.getOrientation();
+
+	  if (! tb.isFloatable())
+	    return new Insets(regular, regular, regular, regular);
+	  else if (orientation == SwingConstants.HORIZONTAL)
+	    return new Insets(regular, offset, regular, regular);
+	  else
+	    return new Insets(offset, regular, regular, regular);
+        }
+
+      return new Insets(0, 0, 0, 0);
+    }
+
+    /**
+     * This method returns whether the border is opaque.
+     *
+     * @return Whether the border is opaque.
+     */
+    public boolean isBorderOpaque()
+    {
+      return false;
+    }
+
+    /**
+     * This method paints the ribbed area of the border.
+     *
+     * @param g The Graphics object to paint with.
+     * @param x The x coordinate of the area.
+     * @param y The y coordinate of the area.
+     * @param w The width of the area.
+     * @param h The height of the area.
+     * @param size The size of the bump.
+     * @param c The color of the bumps.
+     */
+    private void paintBumps(Graphics g, int x, int y, int w, int h, int size,
+                            Color c)
+    {
+      Color saved = g.getColor();
+      g.setColor(c);
+
+      int hgap = 2 * size;
+      int vgap = 4 * size;
+      int count = 0;
+
+      for (int i = x; i < (w + x); i += hgap)
+	for (int j = ((count++ % 2) == 0) ? y : (y + (2 * size)); j < (h + y);
+	     j += vgap)
+	  g.fillRect(i, j, size, size);
+
+      g.setColor(saved);
+    }
+
+    /**
+     * This method paints the border around the given Component.
+     *
+     * @param c The Component whose border is being painted.
+     * @param g The Graphics object to paint with.
+     * @param x The x coordinate of the component.
+     * @param y The y coordinate of the component.
+     * @param width The width of the component.
+     * @param height The height of the component.
+     */
+    public void paintBorder(Component c, Graphics g, int x, int y, int width,
+                            int height)
+    {
+      if (c instanceof JToolBar)
+        {
+	  JToolBar tb = (JToolBar) c;
+
+	  int orientation = tb.getOrientation();
+
+	  if (orientation == SwingConstants.HORIZONTAL)
+	    {
+	      paintBumps(g, x, y, offset, height, 1, Color.WHITE);
+	      paintBumps(g, x + 1, y + 1, offset - 1, height - 1, 1, Color.GRAY);
+	    }
+	  else
+	    {
+	      paintBumps(g, x, y, width, offset, 1, Color.WHITE);
+	      paintBumps(g, x + 1, y + 1, width - 1, offset - 1, 1, Color.GRAY);
+	    }
+        }
+    }
+  }
+}

Added: llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/BasicToolTipUI.java
URL: http://llvm.org/viewvc/llvm-project/llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/BasicToolTipUI.java?rev=43913&view=auto

==============================================================================
--- llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/BasicToolTipUI.java (added)
+++ llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/BasicToolTipUI.java Thu Nov  8 16:56:19 2007
@@ -0,0 +1,245 @@
+/* BasicToolTipUI.java --
+   Copyright (C) 2004, 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package javax.swing.plaf.basic;
+
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.FontMetrics;
+import java.awt.Graphics;
+import java.awt.Insets;
+import java.awt.Rectangle;
+import java.awt.Toolkit;
+
+import javax.swing.JComponent;
+import javax.swing.JToolTip;
+import javax.swing.LookAndFeel;
+import javax.swing.SwingConstants;
+import javax.swing.SwingUtilities;
+import javax.swing.plaf.ComponentUI;
+import javax.swing.plaf.ToolTipUI;
+
+/**
+ * This is the Basic Look and Feel UI class for JToolTip.
+ */
+public class BasicToolTipUI extends ToolTipUI
+{
+
+  /** The shared instance of BasicToolTipUI used for all ToolTips. */
+  private static BasicToolTipUI shared;
+
+  /** The tooltip's text */
+  private String text;
+
+  /**
+   * Creates a new BasicToolTipUI object.
+   */
+  public BasicToolTipUI()
+  {
+    super();
+  }
+
+  /**
+   * This method creates a new BasicToolTip UI for the given 
+   * JComponent.
+   *
+   * @param c The JComponent to create a UI for.
+   *
+   * @return A BasicToolTipUI that can be used by the given JComponent.
+   */
+  public static ComponentUI createUI(JComponent c)
+  {
+    if (shared == null)
+      shared = new BasicToolTipUI();
+    return shared;
+  }
+
+  /**
+   * This method returns the msximum size of the given JComponent.
+   *
+   * @param c The JComponent to find a maximum size for.
+   *
+   * @return The maximum size.
+   */
+  public Dimension getMaximumSize(JComponent c)
+  {
+    return getPreferredSize(c);
+  }
+
+  /**
+   * This method returns the minimum size of the given JComponent.
+   *
+   * @param c The JComponent to find a minimum size for.
+   *
+   * @return The minimum size.
+   */
+  public Dimension getMinimumSize(JComponent c)
+  {
+    return getPreferredSize(c);
+  }
+
+  /**
+   * This method returns the preferred size of the given JComponent.
+   *
+   * @param c The JComponent to find a preferred size for.
+   *
+   * @return The preferred size.
+   */
+  public Dimension getPreferredSize(JComponent c)
+  {
+    JToolTip tip = (JToolTip) c;
+    FontMetrics fm;
+    Toolkit g = tip.getToolkit();
+    text = tip.getTipText();
+    
+    Rectangle vr = new Rectangle();
+    Rectangle ir = new Rectangle();
+    Rectangle tr = new Rectangle();
+    Insets insets = tip.getInsets();
+    fm = g.getFontMetrics(tip.getFont());
+    SwingUtilities.layoutCompoundLabel(tip, fm, text, null,
+                                       SwingConstants.CENTER,
+                                       SwingConstants.CENTER,
+                                       SwingConstants.CENTER,
+                                       SwingConstants.CENTER, vr, ir, tr, 0);
+    return new Dimension(insets.left + tr.width + insets.right,
+                         insets.top + tr.height + insets.bottom);
+  }
+
+  /**
+   * This method installs the defaults for the given JComponent.
+   *
+   * @param c The JComponent to install defaults for.
+   */
+  protected void installDefaults(JComponent c)
+  {
+    LookAndFeel.installColorsAndFont(c, "ToolTip.background",
+                                     "ToolTip.foreground", "ToolTip.font");
+    LookAndFeel.installBorder(c, "ToolTip.border");
+  }
+
+  /**
+   * This method installs the listeners for the given JComponent.
+   *
+   * @param c The JComponent to install listeners for.
+   */
+  protected void installListeners(JComponent c)
+  {
+    // TODO: Implement this properly.
+  }
+
+  /**
+   * This method installs the UI for the given JComponent.
+   *
+   * @param c The JComponent to install the UI for.
+   */
+  public void installUI(JComponent c)
+  {
+    c.setOpaque(true);
+    installDefaults(c);
+    installListeners(c);
+  }
+
+  /**
+   * This method paints the given JComponent with the given Graphics object.
+   *
+   * @param g The Graphics object to paint with.
+   * @param c The JComponent to paint.
+   */
+  public void paint(Graphics g, JComponent c)
+  {
+    JToolTip tip = (JToolTip) c;
+
+    String text = tip.getTipText();
+    Toolkit t = tip.getToolkit();
+    if (text == null)
+      return;
+
+    Rectangle vr = new Rectangle();
+    vr = SwingUtilities.calculateInnerArea(tip, vr);
+    Rectangle ir = new Rectangle();
+    Rectangle tr = new Rectangle();
+    FontMetrics fm = t.getFontMetrics(tip.getFont());
+    int ascent = fm.getAscent();
+    SwingUtilities.layoutCompoundLabel(tip, fm, text, null,
+                                       SwingConstants.CENTER,
+                                       SwingConstants.CENTER,
+                                       SwingConstants.CENTER,
+                                       SwingConstants.CENTER, vr, ir, tr, 0);
+    Color saved = g.getColor();
+    g.setColor(Color.BLACK);
+
+    g.drawString(text, vr.x, vr.y + ascent); 
+
+    g.setColor(saved);   
+  }
+
+  /**
+   * This method uninstalls the defaults for the given JComponent.
+   *
+   * @param c The JComponent to uninstall defaults for.
+   */
+  protected void uninstallDefaults(JComponent c)
+  {
+    c.setForeground(null);
+    c.setBackground(null);
+    c.setFont(null);
+    c.setBorder(null);
+  }
+
+  /**
+   * This method uninstalls listeners for the given JComponent.
+   *
+   * @param c The JComponent to uninstall listeners for.
+   */
+  protected void uninstallListeners(JComponent c)
+  {
+    // TODO: Implement this properly.
+  }
+
+  /**
+   * This method uninstalls the UI for the given JComponent.
+   *
+   * @param c The JComponent to uninstall.
+   */
+  public void uninstallUI(JComponent c)
+  {
+    uninstallDefaults(c);
+    uninstallListeners(c);
+  }
+}

Added: llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/BasicTreeUI.java
URL: http://llvm.org/viewvc/llvm-project/llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/BasicTreeUI.java?rev=43913&view=auto

==============================================================================
--- llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/BasicTreeUI.java (added)
+++ llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/BasicTreeUI.java Thu Nov  8 16:56:19 2007
@@ -0,0 +1,3838 @@
+/* BasicTreeUI.java --
+ Copyright (C) 2002, 2004, 2005, 2006, Free Software Foundation, Inc.
+
+ This file is part of GNU Classpath.
+
+ GNU Classpath is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GNU Classpath is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNU Classpath; see the file COPYING.  If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301 USA.
+
+ Linking this library statically or dynamically with other modules is
+ making a combined work based on this library.  Thus, the terms and
+ conditions of the GNU General Public License cover the whole
+ combination.
+
+ As a special exception, the copyright holders of this library give you
+ permission to link this library with independent modules to produce an
+ executable, regardless of the license terms of these independent
+ modules, and to copy and distribute the resulting executable under
+ terms of your choice, provided that you also meet, for each linked
+ independent module, the terms and conditions of the license of that
+ module.  An independent module is a module which is not derived from
+ or based on this library.  If you modify this library, you may extend
+ this exception to your version of the library, but you are not
+ obligated to do so.  If you do not wish to do so, delete this
+ exception statement from your version. */
+
+
+package javax.swing.plaf.basic;
+
+import gnu.classpath.NotImplementedException;
+import gnu.javax.swing.tree.GnuPath;
+
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Dimension;
+import java.awt.Font;
+import java.awt.FontMetrics;
+import java.awt.Graphics;
+import java.awt.Insets;
+import java.awt.Label;
+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.KeyAdapter;
+import java.awt.event.KeyEvent;
+import java.awt.event.KeyListener;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseListener;
+import java.awt.event.MouseMotionListener;
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+import java.util.Enumeration;
+import java.util.Hashtable;
+
+import javax.swing.AbstractAction;
+import javax.swing.Action;
+import javax.swing.ActionMap;
+import javax.swing.CellRendererPane;
+import javax.swing.Icon;
+import javax.swing.InputMap;
+import javax.swing.JComponent;
+import javax.swing.JScrollBar;
+import javax.swing.JScrollPane;
+import javax.swing.JTree;
+import javax.swing.LookAndFeel;
+import javax.swing.SwingUtilities;
+import javax.swing.Timer;
+import javax.swing.UIManager;
+import javax.swing.event.CellEditorListener;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.MouseInputListener;
+import javax.swing.event.TreeExpansionEvent;
+import javax.swing.event.TreeExpansionListener;
+import javax.swing.event.TreeModelEvent;
+import javax.swing.event.TreeModelListener;
+import javax.swing.event.TreeSelectionEvent;
+import javax.swing.event.TreeSelectionListener;
+import javax.swing.plaf.ActionMapUIResource;
+import javax.swing.plaf.ComponentUI;
+import javax.swing.plaf.TreeUI;
+import javax.swing.tree.AbstractLayoutCache;
+import javax.swing.tree.DefaultTreeCellEditor;
+import javax.swing.tree.DefaultTreeCellRenderer;
+import javax.swing.tree.TreeCellEditor;
+import javax.swing.tree.TreeCellRenderer;
+import javax.swing.tree.TreeModel;
+import javax.swing.tree.TreeNode;
+import javax.swing.tree.TreePath;
+import javax.swing.tree.TreeSelectionModel;
+import javax.swing.tree.VariableHeightLayoutCache;
+
+/**
+ * A delegate providing the user interface for <code>JTree</code> according to
+ * the Basic look and feel.
+ * 
+ * @see javax.swing.JTree
+ * @author Lillian Angel (langel at redhat.com)
+ * @author Sascha Brawer (brawer at dandelis.ch)
+ * @author Audrius Meskauskas (audriusa at bioinformatics.org)
+ */
+public class BasicTreeUI
+    extends TreeUI
+{
+  /**
+   * The tree cell editing may be started by the single mouse click on the
+   * selected cell. To separate it from the double mouse click, the editing
+   * session starts after this time (in ms) after that single click, and only no
+   * other clicks were performed during that time.
+   */
+  static int WAIT_TILL_EDITING = 900;
+
+  /** Collapse Icon for the tree. */
+  protected transient Icon collapsedIcon;
+
+  /** Expanded Icon for the tree. */
+  protected transient Icon expandedIcon;
+
+  /** Distance between left margin and where vertical dashes will be drawn. */
+  protected int leftChildIndent;
+
+  /**
+   * Distance between leftChildIndent and where cell contents will be drawn.
+   */
+  protected int rightChildIndent;
+
+  /**
+   * Total fistance that will be indented. The sum of leftChildIndent and
+   * rightChildIndent .
+   */
+  protected int totalChildIndent;
+
+  /** Index of the row that was last selected. */
+  protected int lastSelectedRow;
+
+  /** Component that we're going to be drawing onto. */
+  protected JTree tree;
+
+  /** Renderer that is being used to do the actual cell drawing. */
+  protected transient TreeCellRenderer currentCellRenderer;
+
+  /**
+   * Set to true if the renderer that is currently in the tree was created by
+   * this instance.
+   */
+  protected boolean createdRenderer;
+
+  /** Editor for the tree. */
+  protected transient TreeCellEditor cellEditor;
+
+  /**
+   * Set to true if editor that is currently in the tree was created by this
+   * instance.
+   */
+  protected boolean createdCellEditor;
+
+  /**
+   * Set to false when editing and shouldSelectCall() returns true meaning the
+   * node should be selected before editing, used in completeEditing.
+   * GNU Classpath editing is implemented differently, so this value is not
+   * actually read anywhere. However it is always set correctly to maintain 
+   * interoperability with the derived classes that read this field.
+   */
+  protected boolean stopEditingInCompleteEditing;
+
+  /** Used to paint the TreeCellRenderer. */
+  protected CellRendererPane rendererPane;
+
+  /** Size needed to completely display all the nodes. */
+  protected Dimension preferredSize;
+
+  /** Minimum size needed to completely display all the nodes. */
+  protected Dimension preferredMinSize;
+
+  /** Is the preferredSize valid? */
+  protected boolean validCachedPreferredSize;
+
+  /** Object responsible for handling sizing and expanded issues. */
+  protected AbstractLayoutCache treeState;
+
+  /** Used for minimizing the drawing of vertical lines. */
+  protected Hashtable drawingCache;
+
+  /**
+   * True if doing optimizations for a largeModel. Subclasses that don't support
+   * this may wish to override createLayoutCache to not return a
+   * FixedHeightLayoutCache instance.
+   */
+  protected boolean largeModel;
+
+  /** Responsible for telling the TreeState the size needed for a node. */
+  protected AbstractLayoutCache.NodeDimensions nodeDimensions;
+
+  /** Used to determine what to display. */
+  protected TreeModel treeModel;
+
+  /** Model maintaining the selection. */
+  protected TreeSelectionModel treeSelectionModel;
+
+  /**
+   * How much the depth should be offset to properly calculate x locations. This
+   * is based on whether or not the root is visible, and if the root handles are
+   * visible.
+   */
+  protected int depthOffset;
+
+  /**
+   * When editing, this will be the Component that is doing the actual editing.
+   */
+  protected Component editingComponent;
+
+  /** Path that is being edited. */
+  protected TreePath editingPath;
+
+  /**
+   * Row that is being edited. Should only be referenced if editingComponent is
+   * null.
+   */
+  protected int editingRow;
+
+  /** Set to true if the editor has a different size than the renderer. */
+  protected boolean editorHasDifferentSize;
+
+  /** Boolean to keep track of editing. */
+  boolean isEditing;
+
+  /** The current path of the visible nodes in the tree. */
+  TreePath currentVisiblePath;
+
+  /** The gap between the icon and text. */
+  int gap = 4;
+
+  /** The max height of the nodes in the tree. */
+  int maxHeight;
+  
+  /** The hash color. */
+  Color hashColor;
+
+  /** Listeners */
+  PropertyChangeListener propertyChangeListener;
+
+  FocusListener focusListener;
+
+  TreeSelectionListener treeSelectionListener;
+
+  MouseListener mouseListener;
+
+  KeyListener keyListener;
+
+  PropertyChangeListener selectionModelPropertyChangeListener;
+
+  ComponentListener componentListener;
+
+  CellEditorListener cellEditorListener;
+
+  TreeExpansionListener treeExpansionListener;
+
+  TreeModelListener treeModelListener;
+
+  /**
+   * This timer fires the editing action after about 1200 ms if not reset during
+   * that time. It handles the editing start with the single mouse click (and
+   * not the double mouse click) on the selected tree node.
+   */
+  Timer startEditTimer;
+  
+  /**
+   * The zero size icon, used for expand controls, if they are not visible.
+   */
+  static Icon nullIcon;
+
+  /**
+   * The special value of the mouse event is sent indicating that this is not
+   * just the mouse click, but the mouse click on the selected node. Sending
+   * such event forces to start the cell editing session.
+   */
+  static final MouseEvent EDIT = new MouseEvent(new Label(), 7, 7, 7, 7, 7, 7,
+                                                false);
+
+  /**
+   * Creates a new BasicTreeUI object.
+   */
+  public BasicTreeUI()
+  {
+    validCachedPreferredSize = false;
+    drawingCache = new Hashtable();
+    nodeDimensions = createNodeDimensions();
+    configureLayoutCache();
+
+    editingRow = - 1;
+    lastSelectedRow = - 1;
+  }
+
+  /**
+   * Returns an instance of the UI delegate for the specified component.
+   * 
+   * @param c the <code>JComponent</code> for which we need a UI delegate for.
+   * @return the <code>ComponentUI</code> for c.
+   */
+  public static ComponentUI createUI(JComponent c)
+  {
+    return new BasicTreeUI();
+  }
+
+  /**
+   * Returns the Hash color.
+   * 
+   * @return the <code>Color</code> of the Hash.
+   */
+  protected Color getHashColor()
+  {
+    return hashColor;
+  }
+
+  /**
+   * Sets the Hash color.
+   * 
+   * @param color the <code>Color</code> to set the Hash to.
+   */
+  protected void setHashColor(Color color)
+  {
+    hashColor = color;
+  }
+
+  /**
+   * Sets the left child's indent value.
+   * 
+   * @param newAmount is the new indent value for the left child.
+   */
+  public void setLeftChildIndent(int newAmount)
+  {
+    leftChildIndent = newAmount;
+  }
+
+  /**
+   * Returns the indent value for the left child.
+   * 
+   * @return the indent value for the left child.
+   */
+  public int getLeftChildIndent()
+  {
+    return leftChildIndent;
+  }
+
+  /**
+   * Sets the right child's indent value.
+   * 
+   * @param newAmount is the new indent value for the right child.
+   */
+  public void setRightChildIndent(int newAmount)
+  {
+    rightChildIndent = newAmount;
+  }
+
+  /**
+   * Returns the indent value for the right child.
+   * 
+   * @return the indent value for the right child.
+   */
+  public int getRightChildIndent()
+  {
+    return rightChildIndent;
+  }
+
+  /**
+   * Sets the expanded icon.
+   * 
+   * @param newG is the new expanded icon.
+   */
+  public void setExpandedIcon(Icon newG)
+  {
+    expandedIcon = newG;
+  }
+
+  /**
+   * Returns the current expanded icon.
+   * 
+   * @return the current expanded icon.
+   */
+  public Icon getExpandedIcon()
+  {
+    return expandedIcon;
+  }
+
+  /**
+   * Sets the collapsed icon.
+   * 
+   * @param newG is the new collapsed icon.
+   */
+  public void setCollapsedIcon(Icon newG)
+  {
+    collapsedIcon = newG;
+  }
+
+  /**
+   * Returns the current collapsed icon.
+   * 
+   * @return the current collapsed icon.
+   */
+  public Icon getCollapsedIcon()
+  {
+    return collapsedIcon;
+  }
+
+  /**
+   * Updates the componentListener, if necessary.
+   * 
+   * @param largeModel sets this.largeModel to it.
+   */
+  protected void setLargeModel(boolean largeModel)
+  {
+    if (largeModel != this.largeModel)
+      {
+        tree.removeComponentListener(componentListener);
+        this.largeModel = largeModel;
+        tree.addComponentListener(componentListener);
+      }
+  }
+
+  /**
+   * Returns true if largeModel is set
+   * 
+   * @return true if largeModel is set, otherwise false.
+   */
+  protected boolean isLargeModel()
+  {
+    return largeModel;
+  }
+
+  /**
+   * Sets the row height.
+   * 
+   * @param rowHeight is the height to set this.rowHeight to.
+   */
+  protected void setRowHeight(int rowHeight)
+  {
+    if (rowHeight == 0)
+      rowHeight = getMaxHeight(tree);
+    treeState.setRowHeight(rowHeight);
+  }
+
+  /**
+   * Returns the current row height.
+   * 
+   * @return current row height.
+   */
+  protected int getRowHeight()
+  {
+    return tree.getRowHeight();
+  }
+
+  /**
+   * Sets the TreeCellRenderer to <code>tcr</code>. This invokes
+   * <code>updateRenderer</code>.
+   * 
+   * @param tcr is the new TreeCellRenderer.
+   */
+  protected void setCellRenderer(TreeCellRenderer tcr)
+  {
+    // Finish editing before changing the renderer.
+    completeEditing();
+
+    // The renderer is set in updateRenderer.
+    updateRenderer();
+
+    // Refresh the layout if necessary.
+    if (treeState != null)
+      {
+	treeState.invalidateSizes();
+	updateSize();
+      }
+  }
+
+  /**
+   * Return currentCellRenderer, which will either be the trees renderer, or
+   * defaultCellRenderer, which ever was not null.
+   * 
+   * @return the current Cell Renderer
+   */
+  protected TreeCellRenderer getCellRenderer()
+  {
+    if (currentCellRenderer != null)
+      return currentCellRenderer;
+
+    return createDefaultCellRenderer();
+  }
+
+  /**
+   * Sets the tree's model.
+   * 
+   * @param model to set the treeModel to.
+   */
+  protected void setModel(TreeModel model)
+  {
+    completeEditing();
+
+    if (treeModel != null && treeModelListener != null)
+      treeModel.removeTreeModelListener(treeModelListener);
+
+    treeModel = tree.getModel();
+
+    if (treeModel != null && treeModelListener != null)
+      treeModel.addTreeModelListener(treeModelListener);
+
+    if (treeState != null)
+      {
+        treeState.setModel(treeModel);
+        updateLayoutCacheExpandedNodes();
+        updateSize();
+      }
+  }
+
+  /**
+   * Returns the tree's model
+   * 
+   * @return treeModel
+   */
+  protected TreeModel getModel()
+  {
+    return treeModel;
+  }
+
+  /**
+   * Sets the root to being visible.
+   * 
+   * @param newValue sets the visibility of the root
+   */
+  protected void setRootVisible(boolean newValue)
+  {
+    tree.setRootVisible(newValue);
+  }
+
+  /**
+   * Returns true if the root is visible.
+   * 
+   * @return true if the root is visible.
+   */
+  protected boolean isRootVisible()
+  {
+    return tree.isRootVisible();
+  }
+
+  /**
+   * Determines whether the node handles are to be displayed.
+   * 
+   * @param newValue sets whether or not node handles should be displayed.
+   */
+  protected void setShowsRootHandles(boolean newValue)
+  {
+    completeEditing();
+    updateDepthOffset();
+    if (treeState != null)
+      {
+        treeState.invalidateSizes();
+        updateSize();
+      }
+  }
+
+  /**
+   * Returns true if the node handles are to be displayed.
+   * 
+   * @return true if the node handles are to be displayed.
+   */
+  protected boolean getShowsRootHandles()
+  {
+    return tree.getShowsRootHandles();
+  }
+
+  /**
+   * Sets the cell editor.
+   * 
+   * @param editor to set the cellEditor to.
+   */
+  protected void setCellEditor(TreeCellEditor editor)
+  {
+    cellEditor = editor;
+    createdCellEditor = true;
+  }
+
+  /**
+   * Returns the <code>TreeCellEditor</code> for this tree.
+   * 
+   * @return the cellEditor for this tree.
+   */
+  protected TreeCellEditor getCellEditor()
+  {
+    return cellEditor;
+  }
+
+  /**
+   * Configures the receiver to allow, or not allow, editing.
+   * 
+   * @param newValue sets the receiver to allow editing if true.
+   */
+  protected void setEditable(boolean newValue)
+  {
+    tree.setEditable(newValue);
+  }
+
+  /**
+   * Returns true if the receiver allows editing.
+   * 
+   * @return true if the receiver allows editing.
+   */
+  protected boolean isEditable()
+  {
+    return tree.isEditable();
+  }
+
+  /**
+   * Resets the selection model. The appropriate listeners are installed on the
+   * model.
+   * 
+   * @param newLSM resets the selection model.
+   */
+  protected void setSelectionModel(TreeSelectionModel newLSM)
+  {
+    if (newLSM != null)
+      {
+        treeSelectionModel = newLSM;
+        tree.setSelectionModel(treeSelectionModel);
+      }
+  }
+
+  /**
+   * Returns the current selection model.
+   * 
+   * @return the current selection model.
+   */
+  protected TreeSelectionModel getSelectionModel()
+  {
+    return treeSelectionModel;
+  }
+
+  /**
+   * Returns the Rectangle enclosing the label portion that the last item in
+   * path will be drawn to. Will return null if any component in path is
+   * currently valid.
+   * 
+   * @param tree is the current tree the path will be drawn to.
+   * @param path is the current path the tree to draw to.
+   * @return the Rectangle enclosing the label portion that the last item in the
+   *         path will be drawn to.
+   */
+  public Rectangle getPathBounds(JTree tree, TreePath path)
+  {
+    return treeState.getBounds(path, new Rectangle());
+  }
+
+  /**
+   * Returns the max height of all the nodes in the tree.
+   * 
+   * @param tree - the current tree
+   * @return the max height.
+   */
+  int getMaxHeight(JTree tree)
+  {
+    if (maxHeight != 0)
+      return maxHeight;
+
+    Icon e = UIManager.getIcon("Tree.openIcon");
+    Icon c = UIManager.getIcon("Tree.closedIcon");
+    Icon l = UIManager.getIcon("Tree.leafIcon");
+    int rc = getRowCount(tree);
+    int iconHeight = 0;
+
+    for (int row = 0; row < rc; row++)
+      {
+        if (isLeaf(row))
+          iconHeight = l.getIconHeight();
+        else if (tree.isExpanded(row))
+          iconHeight = e.getIconHeight();
+        else
+          iconHeight = c.getIconHeight();
+
+        maxHeight = Math.max(maxHeight, iconHeight + gap);
+      }
+     
+    treeState.setRowHeight(maxHeight);
+    return maxHeight;
+  }
+  
+  /**
+   * Get the tree node icon.
+   */
+  Icon getNodeIcon(TreePath path)
+  {
+    Object node = path.getLastPathComponent();
+    if (treeModel.isLeaf(node))
+      return UIManager.getIcon("Tree.leafIcon");
+    else if (treeState.getExpandedState(path))
+      return UIManager.getIcon("Tree.openIcon");
+    else
+      return UIManager.getIcon("Tree.closedIcon");
+  }
+
+  /**
+   * Returns the path for passed in row. If row is not visible null is returned.
+   * 
+   * @param tree is the current tree to return path for.
+   * @param row is the row number of the row to return.
+   * @return the path for passed in row. If row is not visible null is returned.
+   */
+  public TreePath getPathForRow(JTree tree, int row)
+  {
+    return treeState.getPathForRow(row);
+  }
+
+  /**
+   * Returns the row that the last item identified in path is visible at. Will
+   * return -1 if any of the elments in the path are not currently visible.
+   * 
+   * @param tree is the current tree to return the row for.
+   * @param path is the path used to find the row.
+   * @return the row that the last item identified in path is visible at. Will
+   *         return -1 if any of the elments in the path are not currently
+   *         visible.
+   */
+  public int getRowForPath(JTree tree, TreePath path)
+  {
+    return treeState.getRowForPath(path);
+  }
+
+  /**
+   * Returns the number of rows that are being displayed.
+   * 
+   * @param tree is the current tree to return the number of rows for.
+   * @return the number of rows being displayed.
+   */
+  public int getRowCount(JTree tree)
+  {
+    return treeState.getRowCount();
+  }
+
+  /**
+   * Returns the path to the node that is closest to x,y. If there is nothing
+   * currently visible this will return null, otherwise it'll always return a
+   * valid path. If you need to test if the returned object is exactly at x,y
+   * you should get the bounds for the returned path and test x,y against that.
+   * 
+   * @param tree the tree to search for the closest path
+   * @param x is the x coordinate of the location to search
+   * @param y is the y coordinate of the location to search
+   * @return the tree path closes to x,y.
+   */
+  public TreePath getClosestPathForLocation(JTree tree, int x, int y)
+  {
+    return treeState.getPathClosestTo(x, y);
+  }
+
+  /**
+   * Returns true if the tree is being edited. The item that is being edited can
+   * be returned by getEditingPath().
+   * 
+   * @param tree is the tree to check for editing.
+   * @return true if the tree is being edited.
+   */
+  public boolean isEditing(JTree tree)
+  {
+    return isEditing;
+  }
+
+  /**
+   * Stops the current editing session. This has no effect if the tree is not
+   * being edited. Returns true if the editor allows the editing session to
+   * stop.
+   * 
+   * @param tree is the tree to stop the editing on
+   * @return true if the editor allows the editing session to stop.
+   */
+  public boolean stopEditing(JTree tree)
+  {
+    if (isEditing(tree))
+      {
+        completeEditing(false, false, true);
+        finish();
+      }
+    return ! isEditing(tree);
+  }
+
+  /**
+   * Cancels the current editing session.
+   * 
+   * @param tree is the tree to cancel the editing session on.
+   */
+  public void cancelEditing(JTree tree)
+  {
+    // There is no need to send the cancel message to the editor,
+    // as the cancellation event itself arrives from it. This would
+    // only be necessary when cancelling the editing programatically.
+    completeEditing(false, false, false);
+    finish();
+  }
+
+  /**
+   * Selects the last item in path and tries to edit it. Editing will fail if
+   * the CellEditor won't allow it for the selected item.
+   * 
+   * @param tree is the tree to edit on.
+   * @param path is the path in tree to edit on.
+   */
+  public void startEditingAtPath(JTree tree, TreePath path)
+  {
+    startEditing(path, null);
+  }
+
+  /**
+   * Returns the path to the element that is being editted.
+   * 
+   * @param tree is the tree to get the editing path from.
+   * @return the path that is being edited.
+   */
+  public TreePath getEditingPath(JTree tree)
+  {
+    return editingPath;
+  }
+
+  /**
+   * Invoked after the tree instance variable has been set, but before any
+   * default/listeners have been installed.
+   */
+  protected void prepareForUIInstall()
+  {
+    lastSelectedRow = -1;
+    preferredSize = new Dimension();
+    largeModel = tree.isLargeModel();
+    preferredSize = new Dimension();
+    setModel(tree.getModel());
+  }
+
+  /**
+   * Invoked from installUI after all the defaults/listeners have been
+   * installed.
+   */
+  protected void completeUIInstall()
+  {
+    setShowsRootHandles(tree.getShowsRootHandles());
+    updateRenderer();
+    updateDepthOffset();
+    setSelectionModel(tree.getSelectionModel());
+    configureLayoutCache();
+    treeState.setRootVisible(tree.isRootVisible()); 
+    treeSelectionModel.setRowMapper(treeState);
+    updateSize();
+  }
+
+  /**
+   * Invoked from uninstallUI after all the defaults/listeners have been
+   * uninstalled.
+   */
+  protected void completeUIUninstall()
+  {
+    tree = null;
+  }
+
+  /**
+   * Installs the subcomponents of the tree, which is the renderer pane.
+   */
+  protected void installComponents()
+  {
+    currentCellRenderer = createDefaultCellRenderer();
+    rendererPane = createCellRendererPane();
+    createdRenderer = true;
+    setCellRenderer(currentCellRenderer);
+  }
+
+  /**
+   * Creates an instance of NodeDimensions that is able to determine the size of
+   * a given node in the tree. The node dimensions must be created before
+   * configuring the layout cache.
+   * 
+   * @return the NodeDimensions of a given node in the tree
+   */
+  protected AbstractLayoutCache.NodeDimensions createNodeDimensions()
+  {
+    return new NodeDimensionsHandler();
+  }
+
+  /**
+   * Creates a listener that is reponsible for the updates the UI based on how
+   * the tree changes.
+   * 
+   * @return the PropertyChangeListener that is reposnsible for the updates
+   */
+  protected PropertyChangeListener createPropertyChangeListener()
+  {
+    return new PropertyChangeHandler();
+  }
+
+  /**
+   * Creates the listener responsible for updating the selection based on mouse
+   * events.
+   * 
+   * @return the MouseListener responsible for updating.
+   */
+  protected MouseListener createMouseListener()
+  {
+    return new MouseHandler();
+  }
+
+  /**
+   * Creates the listener that is responsible for updating the display when
+   * focus is lost/grained.
+   * 
+   * @return the FocusListener responsible for updating.
+   */
+  protected FocusListener createFocusListener()
+  {
+    return new FocusHandler();
+  }
+
+  /**
+   * Creates the listener reponsible for getting key events from the tree.
+   * 
+   * @return the KeyListener responsible for getting key events.
+   */
+  protected KeyListener createKeyListener()
+  {
+    return new KeyHandler();
+  }
+
+  /**
+   * Creates the listener responsible for getting property change events from
+   * the selection model.
+   * 
+   * @returns the PropertyChangeListener reponsible for getting property change
+   *          events from the selection model.
+   */
+  protected PropertyChangeListener createSelectionModelPropertyChangeListener()
+  {
+    return new SelectionModelPropertyChangeHandler();
+  }
+
+  /**
+   * Creates the listener that updates the display based on selection change
+   * methods.
+   * 
+   * @return the TreeSelectionListener responsible for updating.
+   */
+  protected TreeSelectionListener createTreeSelectionListener()
+  {
+    return new TreeSelectionHandler();
+  }
+
+  /**
+   * Creates a listener to handle events from the current editor
+   * 
+   * @return the CellEditorListener that handles events from the current editor
+   */
+  protected CellEditorListener createCellEditorListener()
+  {
+    return new CellEditorHandler();
+  }
+
+  /**
+   * Creates and returns a new ComponentHandler. This is used for the large
+   * model to mark the validCachedPreferredSize as invalid when the component
+   * moves.
+   * 
+   * @return a new ComponentHandler.
+   */
+  protected ComponentListener createComponentListener()
+  {
+    return new ComponentHandler();
+  }
+
+  /**
+   * Creates and returns the object responsible for updating the treestate when
+   * a nodes expanded state changes.
+   * 
+   * @return the TreeExpansionListener responsible for updating the treestate
+   */
+  protected TreeExpansionListener createTreeExpansionListener()
+  {
+    return new TreeExpansionHandler();
+  }
+
+  /**
+   * Creates the object responsible for managing what is expanded, as well as
+   * the size of nodes.
+   * 
+   * @return the object responsible for managing what is expanded.
+   */
+  protected AbstractLayoutCache createLayoutCache()
+  {
+    return new VariableHeightLayoutCache();
+  }
+
+  /**
+   * Returns the renderer pane that renderer components are placed in.
+   * 
+   * @return the rendererpane that render components are placed in.
+   */
+  protected CellRendererPane createCellRendererPane()
+  {
+    return new CellRendererPane();
+  }
+
+  /**
+   * Creates a default cell editor.
+   * 
+   * @return the default cell editor.
+   */
+  protected TreeCellEditor createDefaultCellEditor()
+  {
+    DefaultTreeCellEditor ed;
+    if (currentCellRenderer != null
+        && currentCellRenderer instanceof DefaultTreeCellRenderer)
+      ed = new DefaultTreeCellEditor(tree,
+                                (DefaultTreeCellRenderer) currentCellRenderer);
+    else
+      ed = new DefaultTreeCellEditor(tree, null);
+    return ed;
+  }
+
+  /**
+   * Returns the default cell renderer that is used to do the stamping of each
+   * node.
+   * 
+   * @return the default cell renderer that is used to do the stamping of each
+   *         node.
+   */
+  protected TreeCellRenderer createDefaultCellRenderer()
+  {
+    return new DefaultTreeCellRenderer();
+  }
+
+  /**
+   * Returns a listener that can update the tree when the model changes.
+   * 
+   * @return a listener that can update the tree when the model changes.
+   */
+  protected TreeModelListener createTreeModelListener()
+  {
+    return new TreeModelHandler();
+  }
+
+  /**
+   * Uninstall all registered listeners
+   */
+  protected void uninstallListeners()
+  {
+    tree.removePropertyChangeListener(propertyChangeListener);
+    tree.removeFocusListener(focusListener);
+    tree.removeTreeSelectionListener(treeSelectionListener);
+    tree.removeMouseListener(mouseListener);
+    tree.removeKeyListener(keyListener);
+    tree.removePropertyChangeListener(selectionModelPropertyChangeListener);
+    tree.removeComponentListener(componentListener);
+    tree.removeTreeExpansionListener(treeExpansionListener);
+
+    TreeCellEditor tce = tree.getCellEditor();
+    if (tce != null)
+      tce.removeCellEditorListener(cellEditorListener);
+    if (treeModel != null)
+      treeModel.removeTreeModelListener(treeModelListener);
+  }
+
+  /**
+   * Uninstall all keyboard actions.
+   */
+  protected void uninstallKeyboardActions()
+  {
+    tree.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).setParent(
+                                                                              null);
+    tree.getActionMap().setParent(null);
+  }
+
+  /**
+   * Uninstall the rendererPane.
+   */
+  protected void uninstallComponents()
+  {
+    currentCellRenderer = null;
+    rendererPane = null;
+    createdRenderer = false;
+    setCellRenderer(currentCellRenderer);
+  }
+
+  /**
+   * The vertical element of legs between nodes starts at the bottom of the
+   * parent node by default. This method makes the leg start below that.
+   * 
+   * @return the vertical leg buffer
+   */
+  protected int getVerticalLegBuffer()
+  {
+    return getRowHeight() / 2;
+  }
+
+  /**
+   * The horizontal element of legs between nodes starts at the right of the
+   * left-hand side of the child node by default. This method makes the leg end
+   * before that.
+   * 
+   * @return the horizontal leg buffer
+   */
+  protected int getHorizontalLegBuffer()
+  {
+    return rightChildIndent / 2;
+  }
+
+  /**
+   * Make all the nodes that are expanded in JTree expanded in LayoutCache. This
+   * invokes updateExpandedDescendants with the root path.
+   */
+  protected void updateLayoutCacheExpandedNodes()
+  {
+    if (treeModel != null && treeModel.getRoot() != null)
+      updateExpandedDescendants(new TreePath(treeModel.getRoot()));
+  }
+
+  /**
+   * Updates the expanded state of all the descendants of the <code>path</code>
+   * by getting the expanded descendants from the tree and forwarding to the
+   * tree state.
+   * 
+   * @param path the path used to update the expanded states
+   */
+  protected void updateExpandedDescendants(TreePath path)
+  {
+    Enumeration expanded = tree.getExpandedDescendants(path);
+    while (expanded.hasMoreElements())
+      treeState.setExpandedState((TreePath) expanded.nextElement(), true);
+  }
+
+  /**
+   * Returns a path to the last child of <code>parent</code>
+   * 
+   * @param parent is the topmost path to specified
+   * @return a path to the last child of parent
+   */
+  protected TreePath getLastChildPath(TreePath parent)
+  {
+    return (TreePath) parent.getLastPathComponent();
+  }
+
+  /**
+   * Updates how much each depth should be offset by.
+   */
+  protected void updateDepthOffset()
+  {
+    depthOffset += getVerticalLegBuffer();
+  }
+
+  /**
+   * Updates the cellEditor based on editability of the JTree that we're
+   * contained in. If the tree is editable but doesn't have a cellEditor, a
+   * basic one will be used.
+   */
+  protected void updateCellEditor()
+  {
+    if (tree.isEditable() && cellEditor == null)
+      setCellEditor(createDefaultCellEditor());
+    createdCellEditor = true;
+  }
+
+  /**
+   * Messaged from the tree we're in when the renderer has changed.
+   */
+  protected void updateRenderer()
+  {
+    if (tree != null)
+      {
+	TreeCellRenderer rend = tree.getCellRenderer();
+	if (rend != null)
+	  {
+	    createdRenderer = false;
+	    currentCellRenderer = rend;
+	    if (createdCellEditor)
+	      tree.setCellEditor(null);
+	  }
+	else
+	  {
+	    tree.setCellRenderer(createDefaultCellRenderer());
+	    createdRenderer = true;
+	  }
+      }
+    else
+      {
+	currentCellRenderer = null;
+	createdRenderer = false;
+      }
+
+    updateCellEditor();
+  }
+
+  /**
+   * Resets the treeState instance based on the tree we're providing the look
+   * and feel for. The node dimensions handler is required and must be created
+   * in advance.
+   */
+  protected void configureLayoutCache()
+  {
+    treeState = createLayoutCache();
+    treeState.setNodeDimensions(nodeDimensions);
+  }
+
+  /**
+   * Marks the cached size as being invalid, and messages the tree with
+   * <code>treeDidChange</code>.
+   */
+  protected void updateSize()
+  {
+    preferredSize = null;
+    updateCachedPreferredSize();
+    tree.treeDidChange();
+  }
+
+  /**
+   * Updates the <code>preferredSize</code> instance variable, which is
+   * returned from <code>getPreferredSize()</code>.
+   */
+  protected void updateCachedPreferredSize()
+  {
+    validCachedPreferredSize = false;
+  }
+
+  /**
+   * Messaged from the VisibleTreeNode after it has been expanded.
+   * 
+   * @param path is the path that has been expanded.
+   */
+  protected void pathWasExpanded(TreePath path)
+  {
+    validCachedPreferredSize = false;
+    treeState.setExpandedState(path, true);
+    tree.repaint();
+  }
+
+  /**
+   * Messaged from the VisibleTreeNode after it has collapsed
+   */
+  protected void pathWasCollapsed(TreePath path)
+  {
+    validCachedPreferredSize = false;
+    treeState.setExpandedState(path, false);
+    tree.repaint();
+  }
+
+  /**
+   * Install all defaults for the tree.
+   */
+  protected void installDefaults()
+  {
+    LookAndFeel.installColorsAndFont(tree, "Tree.background",
+                                     "Tree.foreground", "Tree.font");
+    
+    hashColor = UIManager.getColor("Tree.hash");
+    if (hashColor == null)
+      hashColor = Color.black;
+    
+    tree.setOpaque(true);
+
+    rightChildIndent = UIManager.getInt("Tree.rightChildIndent");
+    leftChildIndent = UIManager.getInt("Tree.leftChildIndent");
+    totalChildIndent = rightChildIndent + leftChildIndent;
+    setRowHeight(UIManager.getInt("Tree.rowHeight"));
+    tree.setRowHeight(getRowHeight());
+    tree.setScrollsOnExpand(UIManager.getBoolean("Tree.scrollsOnExpand"));
+    setExpandedIcon(UIManager.getIcon("Tree.expandedIcon"));
+    setCollapsedIcon(UIManager.getIcon("Tree.collapsedIcon"));
+  }
+
+  /**
+   * Install all keyboard actions for this
+   */
+  protected void installKeyboardActions()
+  {
+    InputMap focusInputMap =
+      (InputMap) SharedUIDefaults.get("Tree.focusInputMap");
+    SwingUtilities.replaceUIInputMap(tree, JComponent.WHEN_FOCUSED,
+                                     focusInputMap);
+    InputMap ancestorInputMap =
+      (InputMap) SharedUIDefaults.get("Tree.ancestorInputMap");
+    SwingUtilities.replaceUIInputMap(tree,
+                                 JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT,
+                                 ancestorInputMap);
+
+    SwingUtilities.replaceUIActionMap(tree, getActionMap());
+  }
+
+  /**
+   * Creates and returns the shared action map for JTrees.
+   *
+   * @return the shared action map for JTrees
+   */
+  private ActionMap getActionMap()
+  {
+    ActionMap am = (ActionMap) UIManager.get("Tree.actionMap");
+    if (am == null)
+      {
+        am = createDefaultActions();
+        UIManager.getLookAndFeelDefaults().put("Tree.actionMap", am);
+      }
+    return am;
+  }
+
+  /**
+   * Creates the default actions when there are none specified by the L&F.
+   *
+   * @return the default actions
+   */
+  private ActionMap createDefaultActions()
+  {
+    ActionMapUIResource am = new ActionMapUIResource();
+    Action action;
+
+    // TreeHomeAction.
+    action = new TreeHomeAction(-1, "selectFirst");
+    am.put(action.getValue(Action.NAME), action);
+    action = new TreeHomeAction(-1, "selectFirstChangeLead");
+    am.put(action.getValue(Action.NAME), action);
+    action = new TreeHomeAction(-1, "selectFirstExtendSelection");
+    am.put(action.getValue(Action.NAME), action);
+    action = new TreeHomeAction(1, "selectLast");
+    am.put(action.getValue(Action.NAME), action);
+    action = new TreeHomeAction(1, "selectLastChangeLead");
+    am.put(action.getValue(Action.NAME), action);
+    action = new TreeHomeAction(1, "selectLastExtendSelection");
+    am.put(action.getValue(Action.NAME), action);
+
+    // TreeIncrementAction.
+    action = new TreeIncrementAction(-1, "selectPrevious");
+    am.put(action.getValue(Action.NAME), action);
+    action = new TreeIncrementAction(-1, "selectPreviousExtendSelection");
+    am.put(action.getValue(Action.NAME), action);
+    action = new TreeIncrementAction(-1, "selectPreviousChangeLead");
+    am.put(action.getValue(Action.NAME), action);
+    action = new TreeIncrementAction(1, "selectNext");
+    am.put(action.getValue(Action.NAME), action);
+    action = new TreeIncrementAction(1, "selectNextExtendSelection");
+    am.put(action.getValue(Action.NAME), action);
+    action = new TreeIncrementAction(1, "selectNextChangeLead");
+    am.put(action.getValue(Action.NAME), action);
+
+    // TreeTraverseAction.
+    action = new TreeTraverseAction(-1, "selectParent");
+    am.put(action.getValue(Action.NAME), action);
+    action = new TreeTraverseAction(1, "selectChild");
+    am.put(action.getValue(Action.NAME), action);
+    
+    // TreeToggleAction.
+    action = new TreeToggleAction("toggleAndAnchor");
+    am.put(action.getValue(Action.NAME), action);
+
+    // TreePageAction.
+    action = new TreePageAction(-1, "scrollUpChangeSelection");
+    am.put(action.getValue(Action.NAME), action);
+    action = new TreePageAction(-1, "scrollUpExtendSelection");
+    am.put(action.getValue(Action.NAME), action);
+    action = new TreePageAction(-1, "scrollUpChangeLead");
+    am.put(action.getValue(Action.NAME), action);
+    action = new TreePageAction(1, "scrollDownChangeSelection");
+    am.put(action.getValue(Action.NAME), action);
+    action = new TreePageAction(1, "scrollDownExtendSelection");
+    am.put(action.getValue(Action.NAME), action);
+    action = new TreePageAction(1, "scrollDownChangeLead");
+    am.put(action.getValue(Action.NAME), action);
+    
+    // Tree editing actions
+    action = new TreeStartEditingAction("startEditing");
+    am.put(action.getValue(Action.NAME), action);
+    action = new TreeCancelEditingAction("cancel");
+    am.put(action.getValue(Action.NAME), action);
+    
+
+    return am;
+  }
+
+  /**
+   * Converts the modifiers.
+   * 
+   * @param mod - modifier to convert
+   * @returns the new modifier
+   */
+  private int convertModifiers(int mod)
+  {
+    if ((mod & KeyEvent.SHIFT_DOWN_MASK) != 0)
+      {
+        mod |= KeyEvent.SHIFT_MASK;
+        mod &= ~ KeyEvent.SHIFT_DOWN_MASK;
+      }
+    if ((mod & KeyEvent.CTRL_DOWN_MASK) != 0)
+      {
+        mod |= KeyEvent.CTRL_MASK;
+        mod &= ~ KeyEvent.CTRL_DOWN_MASK;
+      }
+    if ((mod & KeyEvent.META_DOWN_MASK) != 0)
+      {
+        mod |= KeyEvent.META_MASK;
+        mod &= ~ KeyEvent.META_DOWN_MASK;
+      }
+    if ((mod & KeyEvent.ALT_DOWN_MASK) != 0)
+      {
+        mod |= KeyEvent.ALT_MASK;
+        mod &= ~ KeyEvent.ALT_DOWN_MASK;
+      }
+    if ((mod & KeyEvent.ALT_GRAPH_DOWN_MASK) != 0)
+      {
+        mod |= KeyEvent.ALT_GRAPH_MASK;
+        mod &= ~ KeyEvent.ALT_GRAPH_DOWN_MASK;
+      }
+    return mod;
+  }
+
+  /**
+   * Install all listeners for this
+   */
+  protected void installListeners()
+  {
+    propertyChangeListener = createPropertyChangeListener();
+    tree.addPropertyChangeListener(propertyChangeListener);
+
+    focusListener = createFocusListener();
+    tree.addFocusListener(focusListener);
+
+    treeSelectionListener = createTreeSelectionListener();
+    tree.addTreeSelectionListener(treeSelectionListener);
+
+    mouseListener = createMouseListener();
+    tree.addMouseListener(mouseListener);
+
+    keyListener = createKeyListener();
+    tree.addKeyListener(keyListener);
+
+    selectionModelPropertyChangeListener =
+      createSelectionModelPropertyChangeListener();
+    if (treeSelectionModel != null
+        && selectionModelPropertyChangeListener != null)
+      {
+        treeSelectionModel.addPropertyChangeListener(
+            selectionModelPropertyChangeListener);
+      }
+
+    componentListener = createComponentListener();
+    tree.addComponentListener(componentListener);
+
+    treeExpansionListener = createTreeExpansionListener();
+    tree.addTreeExpansionListener(treeExpansionListener);
+
+    treeModelListener = createTreeModelListener();
+    if (treeModel != null)
+      treeModel.addTreeModelListener(treeModelListener);
+
+    cellEditorListener = createCellEditorListener();
+  }
+
+  /**
+   * Install the UI for the component
+   * 
+   * @param c the component to install UI for
+   */
+  public void installUI(JComponent c)
+  {
+    tree = (JTree) c;
+
+    prepareForUIInstall();
+    installDefaults();
+    installComponents();
+    installKeyboardActions();
+    installListeners();
+    completeUIInstall();
+  }
+  
+  /**
+   * Uninstall the defaults for the tree
+   */
+  protected void uninstallDefaults()
+  {
+    tree.setFont(null);
+    tree.setForeground(null);
+    tree.setBackground(null);
+  }
+
+  /**
+   * Uninstall the UI for the component
+   * 
+   * @param c the component to uninstall UI for
+   */
+  public void uninstallUI(JComponent c)
+  {
+    completeEditing();
+
+    prepareForUIUninstall();
+    uninstallDefaults();
+    uninstallKeyboardActions();
+    uninstallListeners();
+    uninstallComponents();
+    completeUIUninstall();
+  }
+
+  /**
+   * Paints the specified component appropriate for the look and feel. This
+   * method is invoked from the ComponentUI.update method when the specified
+   * component is being painted. Subclasses should override this method and use
+   * the specified Graphics object to render the content of the component.
+   * 
+   * @param g the Graphics context in which to paint
+   * @param c the component being painted; this argument is often ignored, but
+   *          might be used if the UI object is stateless and shared by multiple
+   *          components
+   */
+  public void paint(Graphics g, JComponent c)
+  {
+    JTree tree = (JTree) c;
+    
+    int rows = treeState.getRowCount();
+    
+    if (rows == 0)
+      // There is nothing to do if the tree is empty.
+      return;
+
+    Rectangle clip = g.getClipBounds();
+
+    Insets insets = tree.getInsets();
+
+    if (clip != null && treeModel != null)
+      {
+        int startIndex = tree.getClosestRowForLocation(clip.x, clip.y);
+        int endIndex = tree.getClosestRowForLocation(clip.x + clip.width,
+                                                     clip.y + clip.height);
+
+        // Also paint dashes to the invisible nodes below.
+        // These should be painted first, otherwise they may cover
+        // the control icons.
+        if (endIndex < rows)
+          for (int i = endIndex + 1; i < rows; i++)
+            {
+              TreePath path = treeState.getPathForRow(i);
+              if (isLastChild(path))
+                paintVerticalPartOfLeg(g, clip, insets, path);
+            }
+
+        // The two loops are required to ensure that the lines are not
+        // painted over the other tree components.
+
+        int n = endIndex - startIndex + 1;
+        Rectangle[] bounds = new Rectangle[n];
+        boolean[] isLeaf = new boolean[n];
+        boolean[] isExpanded = new boolean[n];
+        TreePath[] path = new TreePath[n];
+        int k;
+
+        k = 0;
+        for (int i = startIndex; i <= endIndex; i++, k++)
+          {
+            path[k] = treeState.getPathForRow(i);
+            isLeaf[k] = treeModel.isLeaf(path[k].getLastPathComponent());
+            isExpanded[k] = tree.isExpanded(path[k]);
+            bounds[k] = getPathBounds(tree, path[k]);
+
+            paintHorizontalPartOfLeg(g, clip, insets, bounds[k], path[k], i,
+                                     isExpanded[k], false, isLeaf[k]);
+            if (isLastChild(path[k]))
+              paintVerticalPartOfLeg(g, clip, insets, path[k]);
+          }
+
+        k = 0;
+        for (int i = startIndex; i <= endIndex; i++, k++)
+          {
+            paintRow(g, clip, insets, bounds[k], path[k], i, isExpanded[k],
+                     false, isLeaf[k]);
+          }
+      }
+  }
+
+  /**
+   * Check if the path is referring to the last child of some parent.
+   */
+  private boolean isLastChild(TreePath path)
+  {
+    if (path instanceof GnuPath)
+      {
+        // Except the seldom case when the layout cache is changed, this
+        // optimized code will be executed.
+        return ((GnuPath) path).isLastChild;
+      }
+    else
+      {
+        // Non optimized general case.
+        TreePath parent = path.getParentPath();
+        if (parent == null)
+          return false;
+        int childCount = treeState.getVisibleChildCount(parent);
+        int p = treeModel.getIndexOfChild(parent, path.getLastPathComponent());
+        return p == childCount - 1;
+      }
+  }
+
+  /**
+   * Ensures that the rows identified by beginRow through endRow are visible.
+   * 
+   * @param beginRow is the first row
+   * @param endRow is the last row
+   */
+  protected void ensureRowsAreVisible(int beginRow, int endRow)
+  {
+    if (beginRow < endRow)
+      {
+        int temp = endRow;
+        endRow = beginRow;
+        beginRow = temp;
+      }
+
+    for (int i = beginRow; i < endRow; i++)
+      {
+        TreePath path = getPathForRow(tree, i);
+        if (! tree.isVisible(path))
+          tree.makeVisible(path);
+      }
+  }
+
+  /**
+   * Sets the preferred minimum size.
+   * 
+   * @param newSize is the new preferred minimum size.
+   */
+  public void setPreferredMinSize(Dimension newSize)
+  {
+    preferredMinSize = newSize;
+  }
+
+  /**
+   * Gets the preferred minimum size.
+   * 
+   * @returns the preferred minimum size.
+   */
+  public Dimension getPreferredMinSize()
+  {
+    if (preferredMinSize == null)
+      return getPreferredSize(tree);
+    else
+      return preferredMinSize;
+  }
+
+  /**
+   * Returns the preferred size to properly display the tree, this is a cover
+   * method for getPreferredSize(c, false).
+   * 
+   * @param c the component whose preferred size is being queried; this argument
+   *          is often ignored but might be used if the UI object is stateless
+   *          and shared by multiple components
+   * @return the preferred size
+   */
+  public Dimension getPreferredSize(JComponent c)
+  {
+    return getPreferredSize(c, false);
+  }
+
+  /**
+   * Returns the preferred size to represent the tree in c. If checkConsistancy
+   * is true, checkConsistancy is messaged first.
+   * 
+   * @param c the component whose preferred size is being queried.
+   * @param checkConsistancy if true must check consistancy
+   * @return the preferred size
+   */
+  public Dimension getPreferredSize(JComponent c, boolean checkConsistancy)
+  {
+    if (! validCachedPreferredSize)
+      {
+        Rectangle size = tree.getBounds();
+        // Add the scrollbar dimensions to the preferred size.
+        preferredSize = new Dimension(treeState.getPreferredWidth(size),
+                                      treeState.getPreferredHeight());
+        validCachedPreferredSize = true;
+      }
+    return preferredSize;
+  }
+
+  /**
+   * Returns the minimum size for this component. Which will be the min
+   * preferred size or (0,0).
+   * 
+   * @param c the component whose min size is being queried.
+   * @returns the preferred size or null
+   */
+  public Dimension getMinimumSize(JComponent c)
+  {
+    return preferredMinSize = getPreferredSize(c);
+  }
+
+  /**
+   * Returns the maximum size for the component, which will be the preferred
+   * size if the instance is currently in JTree or (0,0).
+   * 
+   * @param c the component whose preferred size is being queried
+   * @return the max size or null
+   */
+  public Dimension getMaximumSize(JComponent c)
+  {
+    return getPreferredSize(c);
+  }
+
+  /**
+   * Messages to stop the editing session. If the UI the receiver is providing
+   * the look and feel for returns true from
+   * <code>getInvokesStopCellEditing</code>, stopCellEditing will be invoked
+   * on the current editor. Then completeEditing will be messaged with false,
+   * true, false to cancel any lingering editing.
+   */
+  protected void completeEditing()
+  {
+    completeEditing(false, true, false);
+  }
+
+  /**
+   * Stops the editing session. If messageStop is true, the editor is messaged
+   * with stopEditing, if messageCancel is true the editor is messaged with
+   * cancelEditing. If messageTree is true, the treeModel is messaged with
+   * valueForPathChanged.
+   * 
+   * @param messageStop message to stop editing
+   * @param messageCancel message to cancel editing
+   * @param messageTree message to treeModel
+   */
+  protected void completeEditing(boolean messageStop, boolean messageCancel,
+                                 boolean messageTree)
+  {
+    // Make no attempt to complete the non existing editing session.
+    if (!isEditing(tree))
+      return;
+    
+    if (messageStop)
+      {
+        getCellEditor().stopCellEditing();
+        stopEditingInCompleteEditing = true;
+      }
+
+    if (messageCancel)
+      {
+        getCellEditor().cancelCellEditing();
+        stopEditingInCompleteEditing = true;
+      }
+
+    if (messageTree)
+      {
+        TreeCellEditor editor = getCellEditor();
+        if (editor != null)
+          {
+            Object value = editor.getCellEditorValue();
+            treeModel.valueForPathChanged(tree.getLeadSelectionPath(), value);
+          }
+      }
+  }
+
+  /**
+   * Will start editing for node if there is a cellEditor and shouldSelectCall
+   * returns true. This assumes that path is valid and visible.
+   * 
+   * @param path is the path to start editing
+   * @param event is the MouseEvent performed on the path
+   * @return true if successful
+   */
+  protected boolean startEditing(TreePath path, MouseEvent event)
+  {
+    updateCellEditor();
+    TreeCellEditor ed = getCellEditor();
+
+    if (ed != null && (event == EDIT || ed.shouldSelectCell(event))
+        && ed.isCellEditable(event))
+      {
+        Rectangle bounds = getPathBounds(tree, path);
+
+        // Extend the right boundary till the tree width.
+        bounds.width = tree.getWidth() - bounds.x;
+
+        editingPath = path;
+        editingRow = tree.getRowForPath(editingPath);
+
+        Object value = editingPath.getLastPathComponent();
+
+        stopEditingInCompleteEditing = false;
+        boolean expanded = tree.isExpanded(editingPath);
+        isEditing = true;
+        editingComponent = ed.getTreeCellEditorComponent(tree, value, true,
+                                                         expanded,
+                                                         isLeaf(editingRow),
+                                                         editingRow);
+
+        // Remove all previous components (if still present). Only one
+        // container with the editing component inside is allowed in the tree.
+        tree.removeAll();
+
+        // The editing component must be added to its container. We add the
+        // container, not the editing component itself.
+        Component container = editingComponent.getParent();
+        container.setBounds(bounds);
+        tree.add(container);
+        editingComponent.requestFocus();
+
+        return true;
+      }
+    return false;
+  }
+
+  /**
+   * If the <code>mouseX</code> and <code>mouseY</code> are in the expand or
+   * collapse region of the row, this will toggle the row.
+   * 
+   * @param path the path we are concerned with
+   * @param mouseX is the cursor's x position
+   * @param mouseY is the cursor's y position
+   */
+  protected void checkForClickInExpandControl(TreePath path, int mouseX,
+                                              int mouseY)
+  {
+    if (isLocationInExpandControl(path, mouseX, mouseY))
+      handleExpandControlClick(path, mouseX, mouseY);
+  }
+
+  /**
+   * Returns true if the <code>mouseX</code> and <code>mouseY</code> fall in
+   * the area of row that is used to expand/collpse the node and the node at row
+   * does not represent a leaf.
+   * 
+   * @param path the path we are concerned with
+   * @param mouseX is the cursor's x position
+   * @param mouseY is the cursor's y position
+   * @return true if the <code>mouseX</code> and <code>mouseY</code> fall in
+   *         the area of row that is used to expand/collpse the node and the
+   *         node at row does not represent a leaf.
+   */
+  protected boolean isLocationInExpandControl(TreePath path, int mouseX,
+                                              int mouseY)
+  {
+    boolean cntlClick = false;
+    if (! treeModel.isLeaf(path.getLastPathComponent()))
+      {
+        int width;
+        Icon expandedIcon = getExpandedIcon();
+        if (expandedIcon != null)
+          width = expandedIcon.getIconWidth();
+        else
+          // Only guessing. This is the width of
+          // the tree control icon in Metal L&F.
+          width = 18;
+
+        Insets i = tree.getInsets();
+        
+        int depth;
+        if (isRootVisible())
+          depth = path.getPathCount()-1;
+        else
+          depth = path.getPathCount()-2;
+        
+        int left = getRowX(tree.getRowForPath(path), depth)
+                   - width + i.left;
+        cntlClick = mouseX >= left && mouseX <= left + width;
+      }
+    return cntlClick;
+  }
+
+  /**
+   * Messaged when the user clicks the particular row, this invokes
+   * toggleExpandState.
+   * 
+   * @param path the path we are concerned with
+   * @param mouseX is the cursor's x position
+   * @param mouseY is the cursor's y position
+   */
+  protected void handleExpandControlClick(TreePath path, int mouseX, int mouseY)
+  {
+    toggleExpandState(path);
+  }
+
+  /**
+   * Expands path if it is not expanded, or collapses row if it is expanded. If
+   * expanding a path and JTree scroll on expand, ensureRowsAreVisible is
+   * invoked to scroll as many of the children to visible as possible (tries to
+   * scroll to last visible descendant of path).
+   * 
+   * @param path the path we are concerned with
+   */
+  protected void toggleExpandState(TreePath path)
+  {
+    // tree.isExpanded(path) would do the same, but treeState knows faster.
+    if (treeState.isExpanded(path))
+      tree.collapsePath(path);
+    else
+      tree.expandPath(path);
+  }
+
+  /**
+   * Returning true signifies a mouse event on the node should toggle the
+   * selection of only the row under the mouse. The BasisTreeUI treats the
+   * event as "toggle selection event" if the CTRL button was pressed while
+   * clicking. The event is not counted as toggle event if the associated
+   * tree does not support the multiple selection.
+   * 
+   * @param event is the MouseEvent performed on the row.
+   * @return true signifies a mouse event on the node should toggle the
+   *         selection of only the row under the mouse.
+   */
+  protected boolean isToggleSelectionEvent(MouseEvent event)
+  {
+    return 
+      (tree.getSelectionModel().getSelectionMode() != 
+        TreeSelectionModel.SINGLE_TREE_SELECTION) &&
+      ((event.getModifiersEx() & InputEvent.CTRL_DOWN_MASK) != 0);  
+  }
+
+  /**
+   * Returning true signifies a mouse event on the node should select from the
+   * anchor point. The BasisTreeUI treats the event as "multiple selection
+   * event" if the SHIFT button was pressed while clicking. The event is not
+   * counted as multiple selection event if the associated tree does not support
+   * the multiple selection.
+   * 
+   * @param event is the MouseEvent performed on the node.
+   * @return true signifies a mouse event on the node should select from the
+   *         anchor point.
+   */
+  protected boolean isMultiSelectEvent(MouseEvent event)
+  {
+    return 
+      (tree.getSelectionModel().getSelectionMode() != 
+        TreeSelectionModel.SINGLE_TREE_SELECTION) &&
+      ((event.getModifiersEx() & InputEvent.SHIFT_DOWN_MASK) != 0);  
+  }
+
+  /**
+   * Returning true indicates the row under the mouse should be toggled based on
+   * the event. This is invoked after checkForClickInExpandControl, implying the
+   * location is not in the expand (toggle) control.
+   * 
+   * @param event is the MouseEvent performed on the row.
+   * @return true indicates the row under the mouse should be toggled based on
+   *         the event.
+   */
+  protected boolean isToggleEvent(MouseEvent event)
+  {
+    boolean toggle = false;
+    if (SwingUtilities.isLeftMouseButton(event))
+      {
+        int clickCount = tree.getToggleClickCount();
+        if (clickCount > 0 && event.getClickCount() == clickCount)
+          toggle = true;
+      }
+    return toggle;
+  }
+
+  /**
+   * Messaged to update the selection based on a MouseEvent over a particular
+   * row. If the even is a toggle selection event, the row is either selected,
+   * or deselected. If the event identifies a multi selection event, the
+   * selection is updated from the anchor point. Otherwise, the row is selected,
+   * and the previous selection is cleared.</p>
+   * 
+   * @param path is the path selected for an event
+   * @param event is the MouseEvent performed on the path.
+   * 
+   * @see #isToggleSelectionEvent(MouseEvent)
+   * @see #isMultiSelectEvent(MouseEvent)
+   */
+  protected void selectPathForEvent(TreePath path, MouseEvent event)
+  {
+    if (isToggleSelectionEvent(event))
+      {
+        // The event selects or unselects the clicked row.
+        if (tree.isPathSelected(path))
+          tree.removeSelectionPath(path);
+        else
+          {
+            tree.addSelectionPath(path);
+            tree.setAnchorSelectionPath(path);
+          }
+      }
+    else if (isMultiSelectEvent(event))
+      {
+        // The event extends selection form anchor till the clicked row.
+        TreePath anchor = tree.getAnchorSelectionPath();
+        if (anchor != null)
+          {
+            int aRow = getRowForPath(tree, anchor);
+            tree.addSelectionInterval(aRow, getRowForPath(tree, path));
+          }
+        else
+          tree.addSelectionPath(path);
+      }
+    else
+      {
+        // This is an ordinary event that just selects the clicked row.
+        tree.setSelectionPath(path);
+        if (isToggleEvent(event))
+          toggleExpandState(path);
+      }
+  }
+
+  /**
+   * Returns true if the node at <code>row</code> is a leaf.
+   * 
+   * @param row is the row we are concerned with.
+   * @return true if the node at <code>row</code> is a leaf.
+   */
+  protected boolean isLeaf(int row)
+  {
+    TreePath pathForRow = getPathForRow(tree, row);
+    if (pathForRow == null)
+      return true;
+
+    Object node = pathForRow.getLastPathComponent();
+    return treeModel.isLeaf(node);
+  }
+  
+  /**
+   * The action to start editing at the current lead selection path.
+   */
+  class TreeStartEditingAction
+      extends AbstractAction
+  {
+    /**
+     * Creates the new tree cancel editing action.
+     * 
+     * @param name the name of the action (used in toString).
+     */
+    public TreeStartEditingAction(String name)
+    {
+      super(name);
+    }    
+    
+    /**
+     * Start editing at the current lead selection path.
+     * 
+     * @param e the ActionEvent that caused this action.
+     */
+    public void actionPerformed(ActionEvent e)
+    {
+      TreePath lead = tree.getLeadSelectionPath();
+      if (!tree.isEditing()) 
+        tree.startEditingAtPath(lead);
+    }
+  }  
+
+  /**
+   * Updates the preferred size when scrolling, if necessary.
+   */
+  public class ComponentHandler
+      extends ComponentAdapter
+      implements ActionListener
+  {
+    /**
+     * Timer used when inside a scrollpane and the scrollbar is adjusting
+     */
+    protected Timer timer;
+
+    /** ScrollBar that is being adjusted */
+    protected JScrollBar scrollBar;
+
+    /**
+     * Constructor
+     */
+    public ComponentHandler()
+    {
+      // Nothing to do here.
+    }
+
+    /**
+     * Invoked when the component's position changes.
+     * 
+     * @param e the event that occurs when moving the component
+     */
+    public void componentMoved(ComponentEvent e)
+    {
+      if (timer == null)
+        {
+          JScrollPane scrollPane = getScrollPane();
+          if (scrollPane == null)
+            updateSize();
+          else
+            {
+              // Determine the scrollbar that is adjusting, if any, and
+              // start the timer for that. If no scrollbar is adjusting,
+              // we simply call updateSize().
+              scrollBar = scrollPane.getVerticalScrollBar();
+              if (scrollBar == null || !scrollBar.getValueIsAdjusting())
+                {
+                  // It's not the vertical scrollbar, try the horizontal one.
+                  scrollBar = scrollPane.getHorizontalScrollBar();
+                  if (scrollBar != null && scrollBar.getValueIsAdjusting())
+                    startTimer();
+                  else
+                    updateSize();
+                }
+              else
+                {
+                  startTimer();
+                }
+            }
+        }
+    }
+
+    /**
+     * Creates, if necessary, and starts a Timer to check if needed to resize
+     * the bounds
+     */
+    protected void startTimer()
+    {
+      if (timer == null)
+        {
+          timer = new Timer(200, this);
+          timer.setRepeats(true);
+        }
+      timer.start();
+    }
+
+    /**
+     * Returns the JScrollPane housing the JTree, or null if one isn't found.
+     * 
+     * @return JScrollPane housing the JTree, or null if one isn't found.
+     */
+    protected JScrollPane getScrollPane()
+    {
+      JScrollPane found = null;
+      Component p = tree.getParent();
+      while (p != null && !(p instanceof JScrollPane))
+        p = p.getParent();
+      if (p instanceof JScrollPane)
+        found = (JScrollPane) p;
+      return found;
+    }
+
+    /**
+     * Public as a result of Timer. If the scrollBar is null, or not adjusting,
+     * this stops the timer and updates the sizing.
+     * 
+     * @param ae is the action performed
+     */
+    public void actionPerformed(ActionEvent ae)
+    {
+      if (scrollBar == null || !scrollBar.getValueIsAdjusting())
+        {
+          if (timer != null)
+            timer.stop();
+          updateSize();
+          timer = null;
+          scrollBar = null;
+        }
+    }
+  }
+
+  /**
+   * Listener responsible for getting cell editing events and updating the tree
+   * accordingly.
+   */
+  public class CellEditorHandler
+      implements CellEditorListener
+  {
+    /**
+     * Constructor
+     */
+    public CellEditorHandler()
+    {
+      // Nothing to do here.
+    }
+
+    /**
+     * Messaged when editing has stopped in the tree. Tells the listeners
+     * editing has stopped.
+     * 
+     * @param e is the notification event
+     */
+    public void editingStopped(ChangeEvent e)
+    {
+      stopEditing(tree);
+    }
+
+    /**
+     * Messaged when editing has been canceled in the tree. This tells the
+     * listeners the editor has canceled editing.
+     * 
+     * @param e is the notification event
+     */
+    public void editingCanceled(ChangeEvent e)
+    {
+      cancelEditing(tree);
+    }
+  } // CellEditorHandler
+
+  /**
+   * Repaints the lead selection row when focus is lost/grained.
+   */
+  public class FocusHandler
+      implements FocusListener
+  {
+    /**
+     * Constructor
+     */
+    public FocusHandler()
+    {
+      // Nothing to do here.
+    }
+
+    /**
+     * Invoked when focus is activated on the tree we're in, redraws the lead
+     * row. Invoked when a component gains the keyboard focus. The method
+     * repaints the lead row that is shown differently when the tree is in
+     * focus.
+     * 
+     * @param e is the focus event that is activated
+     */
+    public void focusGained(FocusEvent e)
+    {
+      repaintLeadRow();
+    }
+
+    /**
+     * Invoked when focus is deactivated on the tree we're in, redraws the lead
+     * row. Invoked when a component loses the keyboard focus. The method
+     * repaints the lead row that is shown differently when the tree is in
+     * focus.
+     * 
+     * @param e is the focus event that is deactivated
+     */
+    public void focusLost(FocusEvent e)
+    {
+      repaintLeadRow();
+    }
+
+    /**
+     * Repaint the lead row.
+     */
+    void repaintLeadRow()
+    {
+      TreePath lead = tree.getLeadSelectionPath();
+      if (lead != null)
+        tree.repaint(tree.getPathBounds(lead));
+    }
+  }
+
+  /**
+   * This is used to get multiple key down events to appropriately genereate
+   * events.
+   */
+  public class KeyHandler
+      extends KeyAdapter
+  {
+    /** Key code that is being generated for. */
+    protected Action repeatKeyAction;
+
+    /** Set to true while keyPressed is active */
+    protected boolean isKeyDown;
+
+    /**
+     * Constructor
+     */
+    public KeyHandler()
+    {
+      // Nothing to do here.
+    }
+
+    /**
+     * Invoked when a key has been typed. Moves the keyboard focus to the first
+     * element whose first letter matches the alphanumeric key pressed by the
+     * user. Subsequent same key presses move the keyboard focus to the next
+     * object that starts with the same letter.
+     * 
+     * @param e the key typed
+     */
+    public void keyTyped(KeyEvent e)
+    {
+      char typed = Character.toLowerCase(e.getKeyChar());
+      for (int row = tree.getLeadSelectionRow() + 1;
+        row < tree.getRowCount(); row++)
+        {
+           if (checkMatch(row, typed))
+             {
+               tree.setSelectionRow(row);
+               tree.scrollRowToVisible(row);
+               return;
+             }
+        }
+      
+      // Not found below, search above:
+      for (int row = 0; row < tree.getLeadSelectionRow(); row++)
+        {
+           if (checkMatch(row, typed))
+             {
+               tree.setSelectionRow(row);
+               tree.scrollRowToVisible(row);               
+               return;
+             }
+        }
+    }
+    
+    /**
+     * Check if the given tree row starts with this character
+     * 
+     * @param row the tree row
+     * @param typed the typed char, must be converted to lowercase
+     * @return true if the given tree row starts with this character
+     */
+    boolean checkMatch(int row, char typed)
+    {
+      TreePath path = treeState.getPathForRow(row);
+      String node = path.getLastPathComponent().toString();
+      if (node.length() > 0)
+        {
+          char x = node.charAt(0);
+          if (typed == Character.toLowerCase(x))
+            return true;
+        }
+      return false;
+    }
+
+    /**
+     * Invoked when a key has been pressed.
+     * 
+     * @param e the key pressed
+     */
+    public void keyPressed(KeyEvent e)
+    {
+      // Nothing to do here.
+    }
+
+    /**
+     * Invoked when a key has been released
+     * 
+     * @param e the key released
+     */
+    public void keyReleased(KeyEvent e)
+    {
+      // Nothing to do here.
+    }
+  }
+
+  /**
+   * MouseListener is responsible for updating the selection based on mouse
+   * events.
+   */
+  public class MouseHandler
+      extends MouseAdapter
+      implements MouseMotionListener
+  {
+    /**
+     * Constructor
+     */
+    public MouseHandler()
+    {
+      // Nothing to do here.
+    }
+
+    /**
+     * Invoked when a mouse button has been pressed on a component.
+     * 
+     * @param e is the mouse event that occured
+     */
+    public void mousePressed(MouseEvent e)
+    {
+      // Any mouse click cancels the previous waiting edit action, initiated
+      // by the single click on the selected node.
+      if (startEditTimer != null)
+        {
+          startEditTimer.stop();
+          startEditTimer = null;
+        }
+
+      if (tree != null && tree.isEnabled())
+        {
+          // Always end the current editing session if clicked on the
+          // tree and outside the bounds of the editing component.
+          if (isEditing(tree))
+            if (!stopEditing(tree))
+            // Return if we have failed to cancel the editing session.
+              return;
+ 
+          int x = e.getX();
+          int y = e.getY();
+          TreePath path = getClosestPathForLocation(tree, x, y);
+
+          if (path != null)
+            {
+              Rectangle bounds = getPathBounds(tree, path);
+              if (SwingUtilities.isLeftMouseButton(e))
+                checkForClickInExpandControl(path, x, y);
+
+              if (x > bounds.x && x <= (bounds.x + bounds.width))
+                {
+                  TreePath currentLead = tree.getLeadSelectionPath();
+                  if (currentLead != null && currentLead.equals(path)
+                      && e.getClickCount() == 1 && tree.isEditable())
+                    {
+                      // Schedule the editing session.
+                      final TreePath editPath = path;
+                      
+                      // The code below handles the required click-pause-click
+                      // functionality which must be present in the tree UI. 
+                      // If the next click comes after the
+                      // time longer than the double click interval AND
+                      // the same node stays focused for the WAIT_TILL_EDITING
+                      // duration, the timer starts the editing session.
+                      if (startEditTimer != null)
+                        startEditTimer.stop();
+
+                      startEditTimer = new Timer(WAIT_TILL_EDITING,
+                         new ActionListener()
+                           {
+                              public void actionPerformed(ActionEvent e)
+                                {
+                                   startEditing(editPath, EDIT);
+                                }
+                            });
+                      
+                      startEditTimer.setRepeats(false);
+                      startEditTimer.start();
+                    }
+                  else
+                    {
+                      if (e.getClickCount() == 2)
+                        toggleExpandState(path);
+                      else
+                        selectPathForEvent(path, e);
+                    }
+                }
+            }
+        }
+
+      // We need to request the focus.
+      tree.requestFocusInWindow();
+    }
+
+    /**
+     * Invoked when a mouse button is pressed on a component and then dragged.
+     * MOUSE_DRAGGED events will continue to be delivered to the component where
+     * the drag originated until the mouse button is released (regardless of
+     * whether the mouse position is within the bounds of the component).
+     * 
+     * @param e is the mouse event that occured
+     */
+    public void mouseDragged(MouseEvent e)
+    throws NotImplementedException
+    {
+      // TODO: What should be done here, if anything?
+    }
+
+    /**
+     * Invoked when the mouse button has been moved on a component (with no
+     * buttons no down).
+     * 
+     * @param e the mouse event that occured
+     */
+    public void mouseMoved(MouseEvent e)
+    throws NotImplementedException
+    {
+      // TODO: What should be done here, if anything?
+    }
+
+    /**
+     * Invoked when a mouse button has been released on a component.
+     * 
+     * @param e is the mouse event that occured
+     */
+    public void mouseReleased(MouseEvent e)
+    throws NotImplementedException
+    {
+      // TODO: What should be done here, if anything?
+    }
+  }
+
+  /**
+   * MouseInputHandler handles passing all mouse events, including mouse motion
+   * events, until the mouse is released to the destination it is constructed
+   * with.
+   */
+  public class MouseInputHandler
+      implements MouseInputListener
+  {
+    /** Source that events are coming from */
+    protected Component source;
+
+    /** Destination that receives all events. */
+    protected Component destination;
+
+    /**
+     * Constructor
+     * 
+     * @param source that events are coming from
+     * @param destination that receives all events
+     * @param e is the event received
+     */
+    public MouseInputHandler(Component source, Component destination,
+                             MouseEvent e)
+    {
+      this.source = source;
+      this.destination = destination;
+    }
+
+    /**
+     * Invoked when the mouse button has been clicked (pressed and released) on
+     * a component.
+     * 
+     * @param e mouse event that occured
+     */
+    public void mouseClicked(MouseEvent e)
+    throws NotImplementedException
+    {
+      // TODO: What should be done here, if anything?
+    }
+
+    /**
+     * Invoked when a mouse button has been pressed on a component.
+     * 
+     * @param e mouse event that occured
+     */
+    public void mousePressed(MouseEvent e)
+    throws NotImplementedException
+    {
+      // TODO: What should be done here, if anything?
+    }
+
+    /**
+     * Invoked when a mouse button has been released on a component.
+     * 
+     * @param e mouse event that occured
+     */
+    public void mouseReleased(MouseEvent e)
+    throws NotImplementedException
+    {
+      // TODO: What should be done here, if anything?
+    }
+
+    /**
+     * Invoked when the mouse enters a component.
+     * 
+     * @param e mouse event that occured
+     */
+    public void mouseEntered(MouseEvent e)
+    throws NotImplementedException
+    {
+      // TODO: What should be done here, if anything?
+    }
+
+    /**
+     * Invoked when the mouse exits a component.
+     * 
+     * @param e mouse event that occured
+     */
+    public void mouseExited(MouseEvent e)
+    throws NotImplementedException
+    {
+      // TODO: What should be done here, if anything?
+    }
+
+    /**
+     * Invoked when a mouse button is pressed on a component and then dragged.
+     * MOUSE_DRAGGED events will continue to be delivered to the component where
+     * the drag originated until the mouse button is released (regardless of
+     * whether the mouse position is within the bounds of the component).
+     * 
+     * @param e mouse event that occured
+     */
+    public void mouseDragged(MouseEvent e)
+    throws NotImplementedException
+    {
+      // TODO: What should be done here, if anything?
+    }
+
+    /**
+     * Invoked when the mouse cursor has been moved onto a component but no
+     * buttons have been pushed.
+     * 
+     * @param e mouse event that occured
+     */
+    public void mouseMoved(MouseEvent e)
+    throws NotImplementedException
+    {
+      // TODO: What should be done here, if anything?
+    }
+
+    /**
+     * Removes event from the source
+     */
+    protected void removeFromSource()
+    throws NotImplementedException
+    {
+      // TODO: Implement this properly.
+    }
+  }
+
+  /**
+   * Class responsible for getting size of node, method is forwarded to
+   * BasicTreeUI method. X location does not include insets, that is handled in
+   * getPathBounds.
+   */
+  public class NodeDimensionsHandler
+      extends AbstractLayoutCache.NodeDimensions
+  {
+    /**
+     * Constructor
+     */
+    public NodeDimensionsHandler()
+    {
+      // Nothing to do here.
+    }
+
+    /**
+     * Returns, by reference in bounds, the size and x origin to place value at.
+     * The calling method is responsible for determining the Y location. If
+     * bounds is null, a newly created Rectangle should be returned, otherwise
+     * the value should be placed in bounds and returned.
+     * 
+     * @param cell the value to be represented
+     * @param row row being queried
+     * @param depth the depth of the row
+     * @param expanded true if row is expanded
+     * @param size a Rectangle containing the size needed to represent value
+     * @return containing the node dimensions, or null if node has no dimension
+     */
+    public Rectangle getNodeDimensions(Object cell, int row, int depth,
+                                       boolean expanded, Rectangle size)
+    {
+      if (size == null || cell == null)
+        return null;
+
+      String s = cell.toString();
+      Font f = tree.getFont();
+      FontMetrics fm = tree.getToolkit().getFontMetrics(f);
+
+      if (s != null)
+        {
+          TreePath path = treeState.getPathForRow(row);
+          size.x = getRowX(row, depth);
+          size.width = SwingUtilities.computeStringWidth(fm, s);
+          size.width = size.width + getCurrentControlIcon(path).getIconWidth()
+                       + gap + getNodeIcon(path).getIconWidth();
+          size.height = getMaxHeight(tree);
+          size.y = size.height * row;
+        }
+
+      return size;
+    }
+
+    /**
+     * Returns the amount to indent the given row
+     * 
+     * @return amount to indent the given row.
+     */
+    protected int getRowX(int row, int depth)
+    {
+      return BasicTreeUI.this.getRowX(row, depth);
+    }
+  } // NodeDimensionsHandler
+
+  /**
+   * PropertyChangeListener for the tree. Updates the appropriate variable, or
+   * TreeState, based on what changes.
+   */
+  public class PropertyChangeHandler
+      implements PropertyChangeListener
+  {
+
+    /**
+     * Constructor
+     */
+    public PropertyChangeHandler()
+    {
+      // Nothing to do here.
+    }
+
+    /**
+     * This method gets called when a bound property is changed.
+     * 
+     * @param event A PropertyChangeEvent object describing the event source and
+     *          the property that has changed.
+     */
+    public void propertyChange(PropertyChangeEvent event)
+    {
+      String property = event.getPropertyName();
+      if (property.equals(JTree.ROOT_VISIBLE_PROPERTY))
+        {
+          validCachedPreferredSize = false;
+          treeState.setRootVisible(tree.isRootVisible());
+          tree.repaint();
+        }
+      else if (property.equals(JTree.SELECTION_MODEL_PROPERTY))
+        {
+          treeSelectionModel = tree.getSelectionModel();
+          treeSelectionModel.setRowMapper(treeState);
+        }
+      else if (property.equals(JTree.TREE_MODEL_PROPERTY))
+        {
+          setModel(tree.getModel());
+        }
+      else if (property.equals(JTree.CELL_RENDERER_PROPERTY))
+        {
+          setCellRenderer(tree.getCellRenderer());
+          // Update layout.
+          if (treeState != null)
+            treeState.invalidateSizes();
+        }
+    }
+  }
+
+  /**
+   * Listener on the TreeSelectionModel, resets the row selection if any of the
+   * properties of the model change.
+   */
+  public class SelectionModelPropertyChangeHandler
+      implements PropertyChangeListener
+  {
+
+    /**
+     * Constructor
+     */
+    public SelectionModelPropertyChangeHandler()
+    {
+      // Nothing to do here.
+    }
+
+    /**
+     * This method gets called when a bound property is changed.
+     * 
+     * @param event A PropertyChangeEvent object describing the event source and
+     *          the property that has changed.
+     */
+    public void propertyChange(PropertyChangeEvent event)
+    throws NotImplementedException
+    {
+      // TODO: What should be done here, if anything?
+    }
+  }
+
+  /**
+   * The action to cancel editing on this tree.
+   */
+  public class TreeCancelEditingAction
+      extends AbstractAction
+  {
+    /**
+     * Creates the new tree cancel editing action.
+     * 
+     * @param name the name of the action (used in toString).
+     */
+    public TreeCancelEditingAction(String name)
+    {
+      super(name);
+    }
+
+    /**
+     * Invoked when an action occurs, cancels the cell editing (if the
+     * tree cell is being edited). 
+     * 
+     * @param e event that occured
+     */
+    public void actionPerformed(ActionEvent e)
+    {
+      if (isEnabled() && tree.isEditing())
+        tree.cancelEditing();
+    }
+  }
+
+  /**
+   * Updates the TreeState in response to nodes expanding/collapsing.
+   */
+  public class TreeExpansionHandler
+      implements TreeExpansionListener
+  {
+
+    /**
+     * Constructor
+     */
+    public TreeExpansionHandler()
+    {
+      // Nothing to do here.
+    }
+
+    /**
+     * Called whenever an item in the tree has been expanded.
+     * 
+     * @param event is the event that occured
+     */
+    public void treeExpanded(TreeExpansionEvent event)
+    {
+      validCachedPreferredSize = false;
+      treeState.setExpandedState(event.getPath(), true);
+      // The maximal cell height may change
+      maxHeight = 0;
+      tree.revalidate();
+      tree.repaint();
+    }
+
+    /**
+     * Called whenever an item in the tree has been collapsed.
+     * 
+     * @param event is the event that occured
+     */
+    public void treeCollapsed(TreeExpansionEvent event)
+    {
+      validCachedPreferredSize = false;
+      treeState.setExpandedState(event.getPath(), false);
+      // The maximal cell height may change
+      maxHeight = 0;
+      tree.revalidate();
+      tree.repaint();
+    }
+  } // TreeExpansionHandler
+
+  /**
+   * TreeHomeAction is used to handle end/home actions. Scrolls either the first
+   * or last cell to be visible based on direction.
+   */
+  public class TreeHomeAction
+      extends AbstractAction
+  {
+
+    /** The direction, either home or end */
+    protected int direction;
+
+    /**
+     * Creates a new TreeHomeAction instance.
+     * 
+     * @param dir the direction to go to, <code>-1</code> for home,
+     *        <code>1</code> for end
+     * @param name the name of the action
+     */
+    public TreeHomeAction(int dir, String name)
+    {
+      direction = dir;
+      putValue(Action.NAME, name);
+    }
+
+    /**
+     * Invoked when an action occurs.
+     * 
+     * @param e is the event that occured
+     */
+    public void actionPerformed(ActionEvent e)
+    {
+      if (tree != null)
+        {
+          String command = (String) getValue(Action.NAME);
+          if (command.equals("selectFirst"))
+            {
+              ensureRowsAreVisible(0, 0);
+              tree.setSelectionInterval(0, 0);
+            }
+          if (command.equals("selectFirstChangeLead"))
+            {
+              ensureRowsAreVisible(0, 0);
+              tree.setLeadSelectionPath(getPathForRow(tree, 0));
+            }
+          if (command.equals("selectFirstExtendSelection"))
+            {
+              ensureRowsAreVisible(0, 0);
+              TreePath anchorPath = tree.getAnchorSelectionPath();
+              if (anchorPath == null)
+                tree.setSelectionInterval(0, 0);
+              else
+                {
+                  int anchorRow = getRowForPath(tree, anchorPath);
+                  tree.setSelectionInterval(0, anchorRow);
+                  tree.setAnchorSelectionPath(anchorPath);
+                  tree.setLeadSelectionPath(getPathForRow(tree, 0));
+                }
+            }
+          else if (command.equals("selectLast"))
+            {
+              int end = getRowCount(tree) - 1;
+              ensureRowsAreVisible(end, end);
+              tree.setSelectionInterval(end, end);
+            }
+          else if (command.equals("selectLastChangeLead"))
+            {
+              int end = getRowCount(tree) - 1;
+              ensureRowsAreVisible(end, end);
+              tree.setLeadSelectionPath(getPathForRow(tree, end));
+            }
+          else if (command.equals("selectLastExtendSelection"))
+            {
+              int end = getRowCount(tree) - 1;
+              ensureRowsAreVisible(end, end);
+              TreePath anchorPath = tree.getAnchorSelectionPath();
+              if (anchorPath == null)
+                tree.setSelectionInterval(end, end);
+              else
+                {
+                  int anchorRow = getRowForPath(tree, anchorPath);
+                  tree.setSelectionInterval(end, anchorRow);
+                  tree.setAnchorSelectionPath(anchorPath);
+                  tree.setLeadSelectionPath(getPathForRow(tree, end));
+                }
+            }
+        }
+
+      // Ensure that the lead path is visible after the increment action.
+      tree.scrollPathToVisible(tree.getLeadSelectionPath());
+    }
+
+    /**
+     * Returns true if the action is enabled.
+     * 
+     * @return true if the action is enabled.
+     */
+    public boolean isEnabled()
+    {
+      return (tree != null) && tree.isEnabled();
+    }
+  }
+
+  /**
+   * TreeIncrementAction is used to handle up/down actions. Selection is moved
+   * up or down based on direction.
+   */
+  public class TreeIncrementAction
+    extends AbstractAction
+  {
+
+    /**
+     * Specifies the direction to adjust the selection by.
+     */
+    protected int direction;
+
+    /**
+     * Creates a new TreeIncrementAction.
+     * 
+     * @param dir up or down, <code>-1</code> for up, <code>1</code> for down
+     * @param name is the name of the direction
+     */
+    public TreeIncrementAction(int dir, String name)
+    {
+      direction = dir;
+      putValue(Action.NAME, name);
+    }
+
+    /**
+     * Invoked when an action occurs.
+     * 
+     * @param e is the event that occured
+     */
+    public void actionPerformed(ActionEvent e)
+    {
+      TreePath currentPath = tree.getLeadSelectionPath();
+      int currentRow;
+
+      if (currentPath != null)
+        currentRow = treeState.getRowForPath(currentPath);
+      else
+        currentRow = 0;
+
+      int rows = treeState.getRowCount();
+
+      int nextRow = currentRow + 1;
+      int prevRow = currentRow - 1;
+      boolean hasNext = nextRow < rows;
+      boolean hasPrev = prevRow >= 0 && rows > 0;
+      TreePath newPath;
+      String command = (String) getValue(Action.NAME);
+
+      if (command.equals("selectPreviousChangeLead") && hasPrev)
+        {
+          newPath = treeState.getPathForRow(prevRow);
+          tree.setSelectionPath(newPath);
+          tree.setAnchorSelectionPath(newPath);
+          tree.setLeadSelectionPath(newPath);
+        }
+      else if (command.equals("selectPreviousExtendSelection") && hasPrev)
+        {
+          newPath = treeState.getPathForRow(prevRow);
+
+          // If the new path is already selected, the selection shrinks,
+          // unselecting the previously current path.
+          if (tree.isPathSelected(newPath))
+            tree.getSelectionModel().removeSelectionPath(currentPath);
+
+          // This must be called in any case because it updates the model
+          // lead selection index.
+          tree.addSelectionPath(newPath);
+          tree.setLeadSelectionPath(newPath);
+        }
+      else if (command.equals("selectPrevious") && hasPrev)
+        {
+          newPath = treeState.getPathForRow(prevRow);
+          tree.setSelectionPath(newPath);
+        }
+      else if (command.equals("selectNext") && hasNext)
+        {
+          newPath = treeState.getPathForRow(nextRow);
+          tree.setSelectionPath(newPath);
+        }
+      else if (command.equals("selectNextExtendSelection") && hasNext)
+        {
+          newPath = treeState.getPathForRow(nextRow);
+
+          // If the new path is already selected, the selection shrinks,
+          // unselecting the previously current path.
+          if (tree.isPathSelected(newPath))
+            tree.getSelectionModel().removeSelectionPath(currentPath);
+
+          // This must be called in any case because it updates the model
+          // lead selection index.
+          tree.addSelectionPath(newPath);
+
+          tree.setLeadSelectionPath(newPath);
+        }
+      else if (command.equals("selectNextChangeLead") && hasNext)
+        {
+          newPath = treeState.getPathForRow(nextRow);
+          tree.setSelectionPath(newPath);
+          tree.setAnchorSelectionPath(newPath);
+          tree.setLeadSelectionPath(newPath);
+        }
+      
+      // Ensure that the lead path is visible after the increment action.
+      tree.scrollPathToVisible(tree.getLeadSelectionPath());
+    }
+
+    /**
+     * Returns true if the action is enabled.
+     * 
+     * @return true if the action is enabled.
+     */
+    public boolean isEnabled()
+    {
+      return (tree != null) && tree.isEnabled();
+    }
+  }
+
+  /**
+   * Forwards all TreeModel events to the TreeState.
+   */
+  public class TreeModelHandler
+      implements TreeModelListener
+  {
+    /**
+     * Constructor
+     */
+    public TreeModelHandler()
+    {
+      // Nothing to do here.
+    }
+
+    /**
+     * Invoked after a node (or a set of siblings) has changed in some way. The
+     * node(s) have not changed locations in the tree or altered their children
+     * arrays, but other attributes have changed and may affect presentation.
+     * Example: the name of a file has changed, but it is in the same location
+     * in the file system. To indicate the root has changed, childIndices and
+     * children will be null. Use e.getPath() to get the parent of the changed
+     * node(s). e.getChildIndices() returns the index(es) of the changed
+     * node(s).
+     * 
+     * @param e is the event that occured
+     */
+    public void treeNodesChanged(TreeModelEvent e)
+    {
+      validCachedPreferredSize = false;
+      treeState.treeNodesChanged(e);
+      tree.repaint();
+    }
+
+    /**
+     * Invoked after nodes have been inserted into the tree. Use e.getPath() to
+     * get the parent of the new node(s). e.getChildIndices() returns the
+     * index(es) of the new node(s) in ascending order.
+     * 
+     * @param e is the event that occured
+     */
+    public void treeNodesInserted(TreeModelEvent e)
+    {
+      validCachedPreferredSize = false;
+      treeState.treeNodesInserted(e);
+      tree.repaint();
+    }
+
+    /**
+     * Invoked after nodes have been removed from the tree. Note that if a
+     * subtree is removed from the tree, this method may only be invoked once
+     * for the root of the removed subtree, not once for each individual set of
+     * siblings removed. Use e.getPath() to get the former parent of the deleted
+     * node(s). e.getChildIndices() returns, in ascending order, the index(es)
+     * the node(s) had before being deleted.
+     * 
+     * @param e is the event that occured
+     */
+    public void treeNodesRemoved(TreeModelEvent e)
+    {
+      validCachedPreferredSize = false;
+      treeState.treeNodesRemoved(e);
+      tree.repaint();
+    }
+
+    /**
+     * Invoked after the tree has drastically changed structure from a given
+     * node down. If the path returned by e.getPath() is of length one and the
+     * first element does not identify the current root node the first element
+     * should become the new root of the tree. Use e.getPath() to get the path
+     * to the node. e.getChildIndices() returns null.
+     * 
+     * @param e is the event that occured
+     */
+    public void treeStructureChanged(TreeModelEvent e)
+    {
+      if (e.getPath().length == 1
+          && ! e.getPath()[0].equals(treeModel.getRoot()))
+        tree.expandPath(new TreePath(treeModel.getRoot()));
+      validCachedPreferredSize = false;
+      treeState.treeStructureChanged(e);
+      tree.repaint();
+    }
+  } // TreeModelHandler
+
+  /**
+   * TreePageAction handles page up and page down events.
+   */
+  public class TreePageAction
+      extends AbstractAction
+  {
+    /** Specifies the direction to adjust the selection by. */
+    protected int direction;
+
+    /**
+     * Constructor
+     * 
+     * @param direction up or down
+     * @param name is the name of the direction
+     */
+    public TreePageAction(int direction, String name)
+    {
+      this.direction = direction;
+      putValue(Action.NAME, name);
+    }
+
+    /**
+     * Invoked when an action occurs.
+     * 
+     * @param e is the event that occured
+     */
+    public void actionPerformed(ActionEvent e)
+    {
+      String command = (String) getValue(Action.NAME);
+      boolean extendSelection = command.equals("scrollUpExtendSelection")
+                                || command.equals("scrollDownExtendSelection");
+      boolean changeSelection = command.equals("scrollUpChangeSelection")
+                                || command.equals("scrollDownChangeSelection");
+
+      // Disable change lead, unless we are in discontinuous mode.
+      if (!extendSelection && !changeSelection
+          && tree.getSelectionModel().getSelectionMode() !=
+            TreeSelectionModel.DISCONTIGUOUS_TREE_SELECTION)
+        {
+          changeSelection = true;
+        }
+
+      int rowCount = getRowCount(tree);
+      if (rowCount > 0 && treeSelectionModel != null)
+        {
+          Dimension maxSize = tree.getSize();
+          TreePath lead = tree.getLeadSelectionPath();
+          TreePath newPath = null;
+          Rectangle visible = tree.getVisibleRect();
+          if (direction == -1) // The RI handles -1 as up.
+            {
+              newPath = getClosestPathForLocation(tree, visible.x, visible.y);
+              if (newPath.equals(lead)) // Corner case, adjust one page up.
+                {
+                  visible.y = Math.max(0, visible.y - visible.height);
+                  newPath = getClosestPathForLocation(tree, visible.x,
+                                                      visible.y);
+                }
+            }
+          else // +1 is down.
+            {
+              visible.y = Math.min(maxSize.height,
+                                   visible.y + visible.height - 1);
+              newPath = getClosestPathForLocation(tree, visible.x, visible.y);
+              if (newPath.equals(lead)) // Corner case, adjust one page down.
+                {
+                  visible.y = Math.min(maxSize.height,
+                                       visible.y + visible.height - 1);
+                  newPath = getClosestPathForLocation(tree, visible.x,
+                                                      visible.y);
+                }
+            }
+
+          // Determine new visible rect.
+          Rectangle newVisible = getPathBounds(tree, newPath);
+          newVisible.x = visible.x;
+          newVisible.width = visible.width;
+          if (direction == -1)
+            {
+              newVisible.height = visible.height;
+            }
+          else
+            {
+              newVisible.y -= visible.height - newVisible.height;
+              newVisible.height = visible.height;
+            }
+
+          if (extendSelection)
+            {
+              // Extend selection.
+              TreePath anchorPath = tree.getAnchorSelectionPath();
+              if (anchorPath == null)
+                {
+                  tree.setSelectionPath(newPath);
+                }
+              else
+                {
+                  int newIndex = getRowForPath(tree, newPath);
+                  int anchorIndex = getRowForPath(tree, anchorPath);
+                  tree.setSelectionInterval(Math.min(anchorIndex, newIndex),
+                                            Math.max(anchorIndex, newIndex));
+                  tree.setAnchorSelectionPath(anchorPath);
+                  tree.setLeadSelectionPath(newPath);
+                }
+            }
+          else if (changeSelection)
+            {
+              tree.setSelectionPath(newPath);
+            }
+          else // Change lead.
+            {
+              tree.setLeadSelectionPath(newPath);
+            }
+
+          tree.scrollRectToVisible(newVisible);
+        }
+    }
+
+    /**
+     * Returns true if the action is enabled.
+     * 
+     * @return true if the action is enabled.
+     */
+    public boolean isEnabled()
+    {
+      return (tree != null) && tree.isEnabled();
+    }
+  } // TreePageAction
+
+  /**
+   * Listens for changes in the selection model and updates the display
+   * accordingly.
+   */
+  public class TreeSelectionHandler
+      implements TreeSelectionListener
+  {
+    /**
+     * Constructor
+     */
+    public TreeSelectionHandler()
+    {
+      // Nothing to do here.
+    }
+
+    /**
+     * Messaged when the selection changes in the tree we're displaying for.
+     * Stops editing, messages super and displays the changed paths.
+     * 
+     * @param event the event that characterizes the change.
+     */
+    public void valueChanged(TreeSelectionEvent event)
+    {
+      if (tree.isEditing())
+        tree.cancelEditing();
+
+      TreePath op = event.getOldLeadSelectionPath();
+      TreePath np = event.getNewLeadSelectionPath();
+      
+      // Repaint of the changed lead selection path.
+      if (op != np)
+        {
+          Rectangle o = treeState.getBounds(event.getOldLeadSelectionPath(), 
+                                           new Rectangle());
+          Rectangle n = treeState.getBounds(event.getNewLeadSelectionPath(), 
+                                           new Rectangle());
+          
+          if (o != null)
+            tree.repaint(o);
+          if (n != null)
+            tree.repaint(n);
+        }
+    }
+  } // TreeSelectionHandler
+
+  /**
+   * For the first selected row expandedness will be toggled.
+   */
+  public class TreeToggleAction
+      extends AbstractAction
+  {
+    /**
+     * Creates a new TreeToggleAction.
+     * 
+     * @param name is the name of <code>Action</code> field
+     */
+    public TreeToggleAction(String name)
+    {
+      putValue(Action.NAME, name);
+    }
+
+    /**
+     * Invoked when an action occurs.
+     * 
+     * @param e the event that occured
+     */
+    public void actionPerformed(ActionEvent e)
+    {
+      int selected = tree.getLeadSelectionRow();
+      if (selected != -1 && isLeaf(selected))
+        {
+          TreePath anchorPath = tree.getAnchorSelectionPath();
+          TreePath leadPath = tree.getLeadSelectionPath();
+          toggleExpandState(getPathForRow(tree, selected));
+          // Need to do this, so that the toggling doesn't mess up the lead
+          // and anchor.
+          tree.setLeadSelectionPath(leadPath);
+          tree.setAnchorSelectionPath(anchorPath);
+
+          // Ensure that the lead path is visible after the increment action.
+          tree.scrollPathToVisible(tree.getLeadSelectionPath());
+        }
+    }
+
+    /**
+     * Returns true if the action is enabled.
+     * 
+     * @return true if the action is enabled, false otherwise
+     */
+    public boolean isEnabled()
+    {
+      return (tree != null) && tree.isEnabled();
+    }
+  } // TreeToggleAction
+
+  /**
+   * TreeTraverseAction is the action used for left/right keys. Will toggle the
+   * expandedness of a node, as well as potentially incrementing the selection.
+   */
+  public class TreeTraverseAction
+      extends AbstractAction
+  {
+    /**
+     * Determines direction to traverse, 1 means expand, -1 means collapse.
+     */
+    protected int direction;
+
+    /**
+     * Constructor
+     * 
+     * @param direction to traverse
+     * @param name is the name of the direction
+     */
+    public TreeTraverseAction(int direction, String name)
+    {
+      this.direction = direction;
+      putValue(Action.NAME, name);
+    }
+
+    /**
+     * Invoked when an action occurs.
+     * 
+     * @param e the event that occured
+     */
+    public void actionPerformed(ActionEvent e)
+    {
+      TreePath current = tree.getLeadSelectionPath();
+      if (current == null)
+        return;
+
+      String command = (String) getValue(Action.NAME);
+      if (command.equals("selectParent"))
+        {
+          if (current == null)
+            return;
+
+          if (tree.isExpanded(current))
+            {
+              tree.collapsePath(current);
+            }
+          else
+            {
+              // If the node is not expanded (also, if it is a leaf node),
+              // we just select the parent. We do not select the root if it
+              // is not visible.
+              TreePath parent = current.getParentPath();
+              if (parent != null && 
+                  ! (parent.getPathCount() == 1 && ! tree.isRootVisible()))
+                tree.setSelectionPath(parent);
+            }
+        }
+      else if (command.equals("selectChild"))
+        {
+          Object node = current.getLastPathComponent();
+          int nc = treeModel.getChildCount(node);
+          if (nc == 0 || treeState.isExpanded(current))
+            {
+              // If the node is leaf or it is already expanded,
+              // we just select the next row.
+              int nextRow = tree.getLeadSelectionRow() + 1;
+              if (nextRow <= tree.getRowCount())
+                tree.setSelectionRow(nextRow);
+            }
+          else
+            {
+              tree.expandPath(current);
+            }
+        }
+      
+      // Ensure that the lead path is visible after the increment action.
+      tree.scrollPathToVisible(tree.getLeadSelectionPath());
+    }
+
+    /**
+     * Returns true if the action is enabled.
+     * 
+     * @return true if the action is enabled, false otherwise
+     */
+    public boolean isEnabled()
+    {
+      return (tree != null) && tree.isEnabled();
+    }
+  }
+
+  /**
+   * Returns true if the LookAndFeel implements the control icons. Package
+   * private for use in inner classes.
+   * 
+   * @returns true if there are control icons
+   */
+  boolean hasControlIcons()
+  {
+    if (expandedIcon != null || collapsedIcon != null)
+      return true;
+    return false;
+  }
+
+  /**
+   * Returns control icon. It is null if the LookAndFeel does not implements the
+   * control icons. Package private for use in inner classes.
+   * 
+   * @return control icon if it exists.
+   */
+  Icon getCurrentControlIcon(TreePath path)
+  {
+    if (hasControlIcons())
+      {
+        if (tree.isExpanded(path))
+          return expandedIcon;
+        else
+          return collapsedIcon;
+      }
+    else
+      {
+        if (nullIcon == null)
+          nullIcon = new Icon()
+          {
+            public int getIconHeight()
+            {
+              return 0;
+            }
+
+            public int getIconWidth()
+            {
+              return 0;
+            }
+
+            public void paintIcon(Component c, Graphics g, int x, int y)
+            {
+              // No action here.
+            }
+          };
+        return nullIcon;
+      }
+  }
+
+  /**
+   * Returns the parent of the current node
+   * 
+   * @param root is the root of the tree
+   * @param node is the current node
+   * @return is the parent of the current node
+   */
+  Object getParent(Object root, Object node)
+  {
+    if (root == null || node == null || root.equals(node))
+      return null;
+
+    if (node instanceof TreeNode)
+      return ((TreeNode) node).getParent();
+    return findNode(root, node);
+  }
+
+  /**
+   * Recursively checks the tree for the specified node, starting at the root.
+   * 
+   * @param root is starting node to start searching at.
+   * @param node is the node to search for
+   * @return the parent node of node
+   */
+  private Object findNode(Object root, Object node)
+  {
+    if (! treeModel.isLeaf(root) && ! root.equals(node))
+      {
+        int size = treeModel.getChildCount(root);
+        for (int j = 0; j < size; j++)
+          {
+            Object child = treeModel.getChild(root, j);
+            if (node.equals(child))
+              return root;
+
+            Object n = findNode(child, node);
+            if (n != null)
+              return n;
+          }
+      }
+    return null;
+  }
+
+  /**
+   * Selects the specified path in the tree depending on modes. Package private
+   * for use in inner classes.
+   * 
+   * @param tree is the tree we are selecting the path in
+   * @param path is the path we are selecting
+   */
+  void selectPath(JTree tree, TreePath path)
+  {
+    if (path != null)
+      {
+        tree.setSelectionPath(path);
+        tree.setLeadSelectionPath(path);        
+        tree.makeVisible(path);
+        tree.scrollPathToVisible(path);
+      }
+  }
+
+  /**
+   * Returns the path from node to the root. Package private for use in inner
+   * classes.
+   * 
+   * @param node the node to get the path to
+   * @param depth the depth of the tree to return a path for
+   * @return an array of tree nodes that represent the path to node.
+   */
+  Object[] getPathToRoot(Object node, int depth)
+  {
+    if (node == null)
+      {
+        if (depth == 0)
+          return null;
+
+        return new Object[depth];
+      }
+
+    Object[] path = getPathToRoot(getParent(treeModel.getRoot(), node),
+                                  depth + 1);
+    path[path.length - depth - 1] = node;
+    return path;
+  }
+
+  /**
+   * Draws a vertical line using the given graphic context
+   * 
+   * @param g is the graphic context
+   * @param c is the component the new line will belong to
+   * @param x is the horizonal position
+   * @param top specifies the top of the line
+   * @param bottom specifies the bottom of the line
+   */
+  protected void paintVerticalLine(Graphics g, JComponent c, int x, int top,
+                                   int bottom)
+  {
+    // FIXME: Check if drawing a dashed line or not.
+    g.setColor(getHashColor());
+    g.drawLine(x, top, x, bottom);
+  }
+
+  /**
+   * Draws a horizontal line using the given graphic context
+   * 
+   * @param g is the graphic context
+   * @param c is the component the new line will belong to
+   * @param y is the vertical position
+   * @param left specifies the left point of the line
+   * @param right specifies the right point of the line
+   */
+  protected void paintHorizontalLine(Graphics g, JComponent c, int y, int left,
+                                     int right)
+  {
+    // FIXME: Check if drawing a dashed line or not.
+    g.setColor(getHashColor());
+    g.drawLine(left, y, right, y);
+  }
+
+  /**
+   * Draws an icon at around a specific position
+   * 
+   * @param c is the component the new line will belong to
+   * @param g is the graphic context
+   * @param icon is the icon which will be drawn
+   * @param x is the center position in x-direction
+   * @param y is the center position in y-direction
+   */
+  protected void drawCentered(Component c, Graphics g, Icon icon, int x, int y)
+  {
+    x -= icon.getIconWidth() / 2;
+    y -= icon.getIconHeight() / 2;
+
+    if (x < 0)
+      x = 0;
+    if (y < 0)
+      y = 0;
+
+    icon.paintIcon(c, g, x, y);
+  }
+
+  /**
+   * Draws a dashed horizontal line.
+   * 
+   * @param g - the graphics configuration.
+   * @param y - the y location to start drawing at
+   * @param x1 - the x location to start drawing at
+   * @param x2 - the x location to finish drawing at
+   */
+  protected void drawDashedHorizontalLine(Graphics g, int y, int x1, int x2)
+  {
+    g.setColor(getHashColor());
+    for (int i = x1; i < x2; i += 2)
+      g.drawLine(i, y, i + 1, y);
+  }
+
+  /**
+   * Draws a dashed vertical line.
+   * 
+   * @param g - the graphics configuration.
+   * @param x - the x location to start drawing at
+   * @param y1 - the y location to start drawing at
+   * @param y2 - the y location to finish drawing at
+   */
+  protected void drawDashedVerticalLine(Graphics g, int x, int y1, int y2)
+  {
+    g.setColor(getHashColor());
+    for (int i = y1; i < y2; i += 2)
+      g.drawLine(x, i, x, i + 1);
+  }
+
+  /**
+   * Paints the expand (toggle) part of a row. The receiver should NOT modify
+   * clipBounds, or insets.
+   * 
+   * @param g - the graphics configuration
+   * @param clipBounds -
+   * @param insets -
+   * @param bounds - bounds of expand control
+   * @param path - path to draw control for
+   * @param row - row to draw control for
+   * @param isExpanded - is the row expanded
+   * @param hasBeenExpanded - has the row already been expanded
+   * @param isLeaf - is the path a leaf
+   */
+  protected void paintExpandControl(Graphics g, Rectangle clipBounds,
+                                    Insets insets, Rectangle bounds,
+                                    TreePath path, int row, boolean isExpanded,
+                                    boolean hasBeenExpanded, boolean isLeaf)
+  {
+    if (shouldPaintExpandControl(path, row, isExpanded, hasBeenExpanded, isLeaf))
+      {
+        Icon icon = getCurrentControlIcon(path);
+        int iconW = icon.getIconWidth();
+        int x = bounds.x - iconW - gap;
+        icon.paintIcon(tree, g, x, bounds.y + bounds.height / 2
+                                   - icon.getIconHeight() / 2);
+      }
+  }
+
+  /**
+   * Paints the horizontal part of the leg. The receiver should NOT modify
+   * clipBounds, or insets. NOTE: parentRow can be -1 if the root is not
+   * visible.
+   * 
+   * @param g - the graphics configuration
+   * @param clipBounds -
+   * @param insets -
+   * @param bounds - bounds of the cell
+   * @param path - path to draw leg for
+   * @param row - row to start drawing at
+   * @param isExpanded - is the row expanded
+   * @param hasBeenExpanded - has the row already been expanded
+   * @param isLeaf - is the path a leaf
+   */
+  protected void paintHorizontalPartOfLeg(Graphics g, Rectangle clipBounds,
+                                          Insets insets, Rectangle bounds,
+                                          TreePath path, int row,
+                                          boolean isExpanded,
+                                          boolean hasBeenExpanded,
+                                          boolean isLeaf)
+  {
+    if (row != 0)
+      {
+        paintHorizontalLine(g, tree, bounds.y + bounds.height / 2,
+                            bounds.x - leftChildIndent - gap, bounds.x - gap);
+      }
+  }
+
+  /**
+   * Paints the vertical part of the leg. The receiver should NOT modify
+   * clipBounds, insets.
+   * 
+   * @param g - the graphics configuration.
+   * @param clipBounds -
+   * @param insets -
+   * @param path - the path to draw the vertical part for.
+   */
+  protected void paintVerticalPartOfLeg(Graphics g, Rectangle clipBounds,
+                                        Insets insets, TreePath path)
+  {
+    Rectangle bounds = getPathBounds(tree, path);
+    TreePath parent = path.getParentPath();
+    
+    boolean paintLine;
+    if (isRootVisible())
+      paintLine = parent != null;
+    else
+      paintLine = parent != null && parent.getPathCount() > 1;
+    if (paintLine)
+      {
+        Rectangle parentBounds = getPathBounds(tree, parent);
+        paintVerticalLine(g, tree, parentBounds.x + 2 * gap, 
+                          parentBounds.y + parentBounds.height / 2,
+                          bounds.y + bounds.height / 2);
+      }
+  }
+
+  /**
+   * Paints the renderer part of a row. The receiver should NOT modify
+   * clipBounds, or insets.
+   * 
+   * @param g - the graphics configuration
+   * @param clipBounds -
+   * @param insets -
+   * @param bounds - bounds of expand control
+   * @param path - path to draw control for
+   * @param row - row to draw control for
+   * @param isExpanded - is the row expanded
+   * @param hasBeenExpanded - has the row already been expanded
+   * @param isLeaf - is the path a leaf
+   */
+  protected void paintRow(Graphics g, Rectangle clipBounds, Insets insets,
+                          Rectangle bounds, TreePath path, int row,
+                          boolean isExpanded, boolean hasBeenExpanded,
+                          boolean isLeaf)
+  {
+    boolean selected = tree.isPathSelected(path);
+    boolean hasIcons = false;
+    Object node = path.getLastPathComponent();
+
+    paintExpandControl(g, clipBounds, insets, bounds, path, row, isExpanded,
+                       hasBeenExpanded, isLeaf);
+
+    TreeCellRenderer dtcr = currentCellRenderer;
+
+    boolean focused = false;
+    if (treeSelectionModel != null)
+      focused = treeSelectionModel.getLeadSelectionRow() == row
+                && tree.isFocusOwner();
+
+    Component c = dtcr.getTreeCellRendererComponent(tree, node, selected,
+                                                    isExpanded, isLeaf, row,
+                                                    focused);
+
+    rendererPane.paintComponent(g, c, c.getParent(), bounds);
+  }
+
+  /**
+   * Prepares for the UI to uninstall.
+   */
+  protected void prepareForUIUninstall()
+  {
+    // Nothing to do here yet.
+  }
+
+  /**
+   * Returns true if the expand (toggle) control should be drawn for the
+   * specified row.
+   * 
+   * @param path - current path to check for.
+   * @param row - current row to check for.
+   * @param isExpanded - true if the path is expanded
+   * @param hasBeenExpanded - true if the path has been expanded already
+   * @param isLeaf - true if the row is a lead
+   */
+  protected boolean shouldPaintExpandControl(TreePath path, int row,
+                                             boolean isExpanded,
+                                             boolean hasBeenExpanded,
+                                             boolean isLeaf)
+  {
+    Object node = path.getLastPathComponent();
+    return ! isLeaf && hasControlIcons();
+  }
+
+  /**
+   * Finish the editing session.
+   */
+  void finish()
+  {
+    treeState.invalidatePathBounds(treeState.getPathForRow(editingRow));
+    editingPath = null;
+    editingRow = - 1;
+    stopEditingInCompleteEditing = false;
+    isEditing = false;
+    Rectangle bounds = editingComponent.getParent().getBounds();
+    tree.removeAll();
+    validCachedPreferredSize = false;
+    // Repaint the region, where was the editing component.
+    tree.repaint(bounds);
+    editingComponent = null;
+    tree.requestFocus();
+  }
+  
+  /**
+   * Returns the amount to indent the given row
+   * 
+   * @return amount to indent the given row.
+   */
+  protected int getRowX(int row, int depth)
+  {
+    return depth * totalChildIndent;
+  }
+} // BasicTreeUI

Added: llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/BasicViewportUI.java
URL: http://llvm.org/viewvc/llvm-project/llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/BasicViewportUI.java?rev=43913&view=auto

==============================================================================
--- llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/BasicViewportUI.java (added)
+++ llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/BasicViewportUI.java Thu Nov  8 16:56:19 2007
@@ -0,0 +1,75 @@
+/* BasicViewportUI.java --
+   Copyright (C) 2002, 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., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package javax.swing.plaf.basic;
+
+import javax.swing.JComponent;
+import javax.swing.LookAndFeel;
+import javax.swing.plaf.ComponentUI;
+import javax.swing.plaf.ViewportUI;
+
+public class BasicViewportUI extends ViewportUI 
+{
+  protected void installDefaults(JComponent c)
+  {
+    c.setOpaque(true);
+    LookAndFeel.installColorsAndFont(c, "Viewport.background",
+                                     "Viewport.foreground", "Viewport.font");
+  }
+  protected void uninstallDefaults(JComponent c)
+  {
+    // TODO: Implement this properly.
+  }
+
+  public static ComponentUI createUI(JComponent c)
+  {
+    return new BasicViewportUI();
+  }
+
+  public void installUI(JComponent c) 
+  {
+    super.installUI(c);
+    installDefaults(c);
+  }
+
+  public void uninstallUI(JComponent c) 
+  {
+    super.uninstallUI(c);
+    uninstallDefaults(c);
+  }
+}

Added: llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/ComboPopup.java
URL: http://llvm.org/viewvc/llvm-project/llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/ComboPopup.java?rev=43913&view=auto

==============================================================================
--- llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/ComboPopup.java (added)
+++ llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/ComboPopup.java Thu Nov  8 16:56:19 2007
@@ -0,0 +1,103 @@
+/* ComboPopup.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., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package javax.swing.plaf.basic;
+
+import java.awt.event.KeyListener;
+import java.awt.event.MouseListener;
+import java.awt.event.MouseMotionListener;
+
+import javax.swing.JList;
+
+public interface ComboPopup
+{
+  /**
+   * This method display popup menu containing list of JComboBox's items to
+   * the screen
+   */
+  void show();
+
+  /**
+   * This method hides popup menu with list of JComboBox's item from the
+   * screen
+   */
+  void hide();
+
+  /**
+   * Retursn true if popup menu with JComboBOx's item is currently visible on
+   * the screen and false otherwise
+   *
+   * @return true if JComboBox's popup menu with list of items is currently
+   *         visible on the screen and false otherwise.
+   */
+  boolean isVisible();
+
+  /**
+   * Return JList that is used to draw cells of the JComboBox.
+   *
+   * @return JList that is used to draw cells of the JcomboBox
+   */
+  JList getList();
+
+  /**
+   * This method returns MouseListener that listen's to mouse events occuring
+   * in the combo box
+   *
+   * @return MouseListenere
+   */
+  MouseListener getMouseListener();
+
+  /**
+   * This method returns MouseListener that listen's to mouse events occuring
+   * in the combo box.
+   *
+   * @return MouseMotionListener
+   */
+  MouseMotionListener getMouseMotionListener();
+
+  /**
+   * This method returns KeyListener that listen's to key events  occuring in
+   * the combo box.
+   *
+   * @return KeyListener
+   */
+  KeyListener getKeyListener();
+
+  /* This method removes any listeners that were installed */
+  void uninstallingUI();
+}

Added: llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/DefaultMenuLayout.java
URL: http://llvm.org/viewvc/llvm-project/llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/DefaultMenuLayout.java?rev=43913&view=auto

==============================================================================
--- llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/DefaultMenuLayout.java (added)
+++ llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/DefaultMenuLayout.java Thu Nov  8 16:56:19 2007
@@ -0,0 +1,78 @@
+/* DefaultMenuLayout.java
+   Copyright (C) 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+package javax.swing.plaf.basic;
+
+import java.awt.Container;
+import java.awt.Dimension;
+
+import javax.swing.BoxLayout;
+import javax.swing.plaf.UIResource;
+
+/**
+ * The LayoutManager that is used in PopupMenus. This is a derived from
+ * {@link BoxLayout}.
+ *
+ * @author Roman Kennke (roman at kennke.org)
+ */
+public class DefaultMenuLayout
+  extends BoxLayout
+  implements UIResource
+{
+
+  /**
+   * Creates a new instance of DefaultMenuLayout.
+   *
+   * @param target the component that is laid out
+   * @param axis the axis along which the component is laid out
+   */
+  public DefaultMenuLayout(Container target, int axis)
+  {
+    super(target, axis);
+  }
+
+  /**
+   * Returns the preferred size for the layout of the menu.
+   *
+   * @param target the Container which's preferred size we calculate
+   */
+  public Dimension preferredLayoutSize(Container target)
+  {
+    return super.preferredLayoutSize(target);
+  }
+
+}

Added: llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/SharedUIDefaults.java
URL: http://llvm.org/viewvc/llvm-project/llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/SharedUIDefaults.java?rev=43913&view=auto

==============================================================================
--- llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/SharedUIDefaults.java (added)
+++ llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/SharedUIDefaults.java Thu Nov  8 16:56:19 2007
@@ -0,0 +1,91 @@
+/* SharedUIDefaults.java -- Manages shared instances for UIDefaults
+   Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package javax.swing.plaf.basic;
+
+import java.awt.Color;
+import java.util.HashMap;
+
+import javax.swing.UIManager;
+
+/**
+ * Manages shared instances for UI defaults. For example, all Swing components
+ * of one type usually share one InputMap/ActionMap pair. In order to avoid
+ * duplication of such objects we store them in a Map here.
+ *
+ * @author Roman Kennke (kennke at aicas.com)
+ */
+public class SharedUIDefaults
+{
+
+  /**
+   * Stores the shared instances, indexed by their UI names
+   * (i.e. "TextField.InputMap").
+   */
+  private static HashMap sharedDefaults = new HashMap();
+
+  /**
+   * Returns a shared UI defaults object.
+   *
+   * @param key the key for the shared object
+   *
+   * @return a shared UI defaults object for the specified key
+   */
+  static Object get(String key)
+  {
+    Object o = sharedDefaults.get(key);
+    if (o == null)
+      {
+        o = UIManager.get(key);
+        sharedDefaults.put(key, o);
+      }
+    return o;
+  }
+
+  /**
+   * Returns a shared UI color.
+   *
+   * @param key the key
+   *
+   * @return the shared color instance
+   */
+  static Color getColor(String key)
+  {
+    return (Color) get(key);
+  }
+}

Added: llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/doc-files/BasicBorders-1.png
URL: http://llvm.org/viewvc/llvm-project/llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/doc-files/BasicBorders-1.png?rev=43913&view=auto

==============================================================================
Binary file - no diff available.

Propchange: llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/doc-files/BasicBorders-1.png

------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/doc-files/BasicBorders-2.png
URL: http://llvm.org/viewvc/llvm-project/llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/doc-files/BasicBorders-2.png?rev=43913&view=auto

==============================================================================
Binary file - no diff available.

Propchange: llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/doc-files/BasicBorders-2.png

------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/doc-files/BasicBorders.ButtonBorder-1.png
URL: http://llvm.org/viewvc/llvm-project/llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/doc-files/BasicBorders.ButtonBorder-1.png?rev=43913&view=auto

==============================================================================
Binary file - no diff available.

Propchange: llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/doc-files/BasicBorders.ButtonBorder-1.png

------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/doc-files/BasicBorders.FieldBorder-1.png
URL: http://llvm.org/viewvc/llvm-project/llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/doc-files/BasicBorders.FieldBorder-1.png?rev=43913&view=auto

==============================================================================
Binary file - no diff available.

Propchange: llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/doc-files/BasicBorders.FieldBorder-1.png

------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/doc-files/BasicBorders.MarginBorder-1.png
URL: http://llvm.org/viewvc/llvm-project/llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/doc-files/BasicBorders.MarginBorder-1.png?rev=43913&view=auto

==============================================================================
Binary file - no diff available.

Propchange: llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/doc-files/BasicBorders.MarginBorder-1.png

------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/doc-files/BasicBorders.MenuBarBorder-1.png
URL: http://llvm.org/viewvc/llvm-project/llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/doc-files/BasicBorders.MenuBarBorder-1.png?rev=43913&view=auto

==============================================================================
Binary file - no diff available.

Propchange: llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/doc-files/BasicBorders.MenuBarBorder-1.png

------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/doc-files/BasicBorders.RadioButtonBorder-1.png
URL: http://llvm.org/viewvc/llvm-project/llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/doc-files/BasicBorders.RadioButtonBorder-1.png?rev=43913&view=auto

==============================================================================
Binary file - no diff available.

Propchange: llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/doc-files/BasicBorders.RadioButtonBorder-1.png

------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/doc-files/BasicBorders.SplitPaneBorder-1.png
URL: http://llvm.org/viewvc/llvm-project/llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/doc-files/BasicBorders.SplitPaneBorder-1.png?rev=43913&view=auto

==============================================================================
Binary file - no diff available.

Propchange: llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/doc-files/BasicBorders.SplitPaneBorder-1.png

------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/doc-files/BasicBorders.SplitPaneBorder-2.png
URL: http://llvm.org/viewvc/llvm-project/llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/doc-files/BasicBorders.SplitPaneBorder-2.png?rev=43913&view=auto

==============================================================================
Binary file - no diff available.

Propchange: llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/doc-files/BasicBorders.SplitPaneBorder-2.png

------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/doc-files/BasicBorders.SplitPaneDividerBorder-1.png
URL: http://llvm.org/viewvc/llvm-project/llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/doc-files/BasicBorders.SplitPaneDividerBorder-1.png?rev=43913&view=auto

==============================================================================
Binary file - no diff available.

Propchange: llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/doc-files/BasicBorders.SplitPaneDividerBorder-1.png

------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/doc-files/BasicBorders.ToggleButtonBorder-1.png
URL: http://llvm.org/viewvc/llvm-project/llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/doc-files/BasicBorders.ToggleButtonBorder-1.png?rev=43913&view=auto

==============================================================================
Binary file - no diff available.

Propchange: llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/doc-files/BasicBorders.ToggleButtonBorder-1.png

------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/doc-files/BasicGraphicsUtils-1.png
URL: http://llvm.org/viewvc/llvm-project/llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/doc-files/BasicGraphicsUtils-1.png?rev=43913&view=auto

==============================================================================
Binary file - no diff available.

Propchange: llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/doc-files/BasicGraphicsUtils-1.png

------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/doc-files/BasicGraphicsUtils-2.png
URL: http://llvm.org/viewvc/llvm-project/llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/doc-files/BasicGraphicsUtils-2.png?rev=43913&view=auto

==============================================================================
Binary file - no diff available.

Propchange: llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/doc-files/BasicGraphicsUtils-2.png

------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/doc-files/BasicGraphicsUtils-3.png
URL: http://llvm.org/viewvc/llvm-project/llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/doc-files/BasicGraphicsUtils-3.png?rev=43913&view=auto

==============================================================================
Binary file - no diff available.

Propchange: llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/doc-files/BasicGraphicsUtils-3.png

------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/doc-files/BasicGraphicsUtils-4.png
URL: http://llvm.org/viewvc/llvm-project/llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/doc-files/BasicGraphicsUtils-4.png?rev=43913&view=auto

==============================================================================
Binary file - no diff available.

Propchange: llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/doc-files/BasicGraphicsUtils-4.png

------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/doc-files/BasicGraphicsUtils-5.png
URL: http://llvm.org/viewvc/llvm-project/llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/doc-files/BasicGraphicsUtils-5.png?rev=43913&view=auto

==============================================================================
Binary file - no diff available.

Propchange: llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/doc-files/BasicGraphicsUtils-5.png

------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/doc-files/BasicGraphicsUtils-6.png
URL: http://llvm.org/viewvc/llvm-project/llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/doc-files/BasicGraphicsUtils-6.png?rev=43913&view=auto

==============================================================================
Binary file - no diff available.

Propchange: llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/doc-files/BasicGraphicsUtils-6.png

------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/doc-files/BasicGraphicsUtils-7.png
URL: http://llvm.org/viewvc/llvm-project/llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/doc-files/BasicGraphicsUtils-7.png?rev=43913&view=auto

==============================================================================
Binary file - no diff available.

Propchange: llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/doc-files/BasicGraphicsUtils-7.png

------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/package.html
URL: http://llvm.org/viewvc/llvm-project/llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/package.html?rev=43913&view=auto

==============================================================================
--- llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/package.html (added)
+++ llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/basic/package.html Thu Nov  8 16:56:19 2007
@@ -0,0 +1,46 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<!-- package.html - describes classes in javax.swing.plaf.basic package.
+   Copyright (C) 2002, 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. -->
+
+<html>
+<head><title>GNU Classpath - javax.swing.plaf.basic</title></head>
+
+<body>
+<p>Provides a "basic" look and feel implementation.</p>
+
+</body>
+</html>

Added: llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/doc-files/ComponentUI-1.dia
URL: http://llvm.org/viewvc/llvm-project/llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/doc-files/ComponentUI-1.dia?rev=43913&view=auto

==============================================================================
Binary file - no diff available.

Propchange: llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/doc-files/ComponentUI-1.dia

------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/doc-files/ComponentUI-1.png
URL: http://llvm.org/viewvc/llvm-project/llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/doc-files/ComponentUI-1.png?rev=43913&view=auto

==============================================================================
Binary file - no diff available.

Propchange: llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/doc-files/ComponentUI-1.png

------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/doc-files/TreeUI-1.png
URL: http://llvm.org/viewvc/llvm-project/llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/doc-files/TreeUI-1.png?rev=43913&view=auto

==============================================================================
Binary file - no diff available.

Propchange: llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/doc-files/TreeUI-1.png

------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/metal/DefaultMetalTheme.java
URL: http://llvm.org/viewvc/llvm-project/llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/metal/DefaultMetalTheme.java?rev=43913&view=auto

==============================================================================
--- llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/metal/DefaultMetalTheme.java (added)
+++ llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/metal/DefaultMetalTheme.java Thu Nov  8 16:56:19 2007
@@ -0,0 +1,221 @@
+/* DefaultMetalTheme.java --
+   Copyright (C) 2004, 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package javax.swing.plaf.metal;
+
+import java.awt.Font;
+
+import javax.swing.plaf.ColorUIResource;
+import javax.swing.plaf.FontUIResource;
+
+/**
+ * The default theme for the {@link MetalLookAndFeel}.
+ * 
+ * @see MetalLookAndFeel#setCurrentTheme(MetalTheme)
+ */
+public class DefaultMetalTheme extends MetalTheme
+{
+  private static final ColorUIResource PRIMARY1 =
+    new ColorUIResource(102, 102, 153);
+  private static final ColorUIResource PRIMARY2 =
+    new ColorUIResource(153, 153, 204);
+  private static final ColorUIResource PRIMARY3 = 
+    new ColorUIResource(204, 204, 255);
+  private static final ColorUIResource SECONDARY1 = 
+    new ColorUIResource(102, 102, 102);
+  private static final ColorUIResource SECONDARY2 = 
+    new ColorUIResource(153, 153, 153);
+  private static final ColorUIResource SECONDARY3 = 
+    new ColorUIResource(204, 204, 204);
+  
+  private static final FontUIResource CONTROL_TEXT_FONT =
+    new FontUIResource("Dialog", Font.BOLD, 12);
+  private static final FontUIResource MENU_TEXT_FONT =
+    new FontUIResource("Dialog", Font.BOLD, 12);
+  private static final FontUIResource SUB_TEXT_FONT =
+    new FontUIResource("Dialog", Font.PLAIN, 10);
+  private static final FontUIResource SYSTEM_TEXT_FONT =
+    new FontUIResource("Dialog", Font.PLAIN, 12);
+  private static final FontUIResource USER_TEXT_FONT =
+    new FontUIResource("Dialog", Font.PLAIN, 12);
+  private static final FontUIResource WINDOW_TITLE_FONT =
+    new FontUIResource("Dialog", Font.BOLD, 12);
+  
+  /**
+   * Creates a new instance of this theme.
+   */
+  public DefaultMetalTheme()
+  {
+    // Do nothing here.
+  }
+
+  /**
+   * Returns the name of the theme.
+   * 
+   * @return <code>"Steel"</code>.
+   */
+  public String getName()
+  {
+    return "Steel";
+  }
+
+  /**
+   * Returns the first primary color for this theme.
+   * 
+   * @return The first primary color.
+   */
+  protected ColorUIResource getPrimary1()
+  {
+    return PRIMARY1;
+  }
+
+  /**
+   * Returns the second primary color for this theme.
+   * 
+   * @return The second primary color.
+   */
+  protected ColorUIResource getPrimary2()
+  {
+    return PRIMARY2;
+  }
+
+  /**
+   * Returns the third primary color for this theme.
+   * 
+   * @return The third primary color.
+   */
+  protected ColorUIResource getPrimary3()
+  {
+    return PRIMARY3;
+  }
+
+  /**
+   * Returns the first secondary color for this theme.
+   * 
+   * @return The first secondary color.
+   */
+  protected ColorUIResource getSecondary1()
+  {
+    return SECONDARY1;
+  }
+
+  /**
+   * Returns the second secondary color for this theme.
+   * 
+   * @return The second secondary color.
+   */
+  protected ColorUIResource getSecondary2()
+  {
+    return SECONDARY2;
+  }
+
+  /**
+   * Returns the third secondary color for this theme.
+   * 
+   * @return The third secondary color.
+   */
+  protected ColorUIResource getSecondary3()
+  {
+    return SECONDARY3;
+  }
+
+  /**
+   * Returns the font used for text on controls.  In this case, the font is
+   * <code>FontUIResource("Dialog", Font.BOLD, 12)</code>.
+   * 
+   * @return The font.
+   */
+  public FontUIResource getControlTextFont()
+  {
+    return CONTROL_TEXT_FONT;
+  }
+  /**
+   * Returns the font used for text in menus.  In this case, the font is
+   * <code>FontUIResource("Dialog", Font.BOLD, 12)</code>.
+   * 
+   * @return The font used for text in menus.
+   */
+  public FontUIResource getMenuTextFont()
+  {
+    return MENU_TEXT_FONT;
+  }
+  
+  /**
+   * Returns the font used for sub text.  In this case, the font is
+   * <code>FontUIResource("Dialog", Font.PLAIN, 10)</code>.
+   * 
+   * @return The font used for sub text.
+   */
+  public FontUIResource getSubTextFont()
+  {
+    return SUB_TEXT_FONT;
+  }
+  
+  /**
+   * Returns the font used for system text.  In this case, the font is
+   * <code>FontUIResource("Dialog", Font.PLAIN, 12)</code>.
+   * 
+   * @return The font used for system text.
+   */
+  public FontUIResource getSystemTextFont()
+  {
+    return SYSTEM_TEXT_FONT;
+  }
+  
+  /**
+   * Returns the font used for user text.  In this case, the font is
+   * <code>FontUIResource("Dialog", Font.PLAIN, 12)</code>.
+   * 
+   * @return The font used for user text. 
+   */
+  public FontUIResource getUserTextFont()
+  {
+    return USER_TEXT_FONT;
+  }
+  
+  /**
+   * Returns the font used for window titles.  In this case, the font is 
+   * <code>FontUIResource("Dialog", Font.BOLD, 12)</code>.
+   * 
+   * @return The font used for window titles.
+   */
+  public FontUIResource getWindowTitleFont()
+  {
+    return WINDOW_TITLE_FONT;
+  }
+}

Added: llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/metal/MetalBorders.java
URL: http://llvm.org/viewvc/llvm-project/llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/metal/MetalBorders.java?rev=43913&view=auto

==============================================================================
--- llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/metal/MetalBorders.java (added)
+++ llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/metal/MetalBorders.java Thu Nov  8 16:56:19 2007
@@ -0,0 +1,1620 @@
+/* MetalBorders.java
+   Copyright (C) 2005, 2006, Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package javax.swing.plaf.metal;
+
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Graphics;
+import java.awt.Insets;
+
+import javax.swing.AbstractButton;
+import javax.swing.ButtonModel;
+import javax.swing.JButton;
+import javax.swing.JInternalFrame;
+import javax.swing.JMenu;
+import javax.swing.JMenuBar;
+import javax.swing.JMenuItem;
+import javax.swing.JOptionPane;
+import javax.swing.JScrollPane;
+import javax.swing.JTextField;
+import javax.swing.JToggleButton;
+import javax.swing.JToolBar;
+import javax.swing.SwingConstants;
+import javax.swing.UIManager;
+import javax.swing.border.AbstractBorder;
+import javax.swing.border.Border;
+import javax.swing.border.CompoundBorder;
+import javax.swing.plaf.BorderUIResource;
+import javax.swing.plaf.UIResource;
+import javax.swing.plaf.basic.BasicBorders;
+import javax.swing.text.JTextComponent;
+
+
+/**
+ * A factory class that creates borders for the different Swing components.
+ *
+ * @author Roman Kennke (roman at kennke.org)
+ */
+public class MetalBorders
+{
+
+  /** The shared instance for getButtonBorder(). */
+  private static Border buttonBorder;
+
+  /** The shared instance for getToggleButtonBorder(). */
+  private static Border toggleButtonBorder;
+
+  /** The shared instance for getDesktopIconBorder(). */
+  private static Border desktopIconBorder;
+
+  /** The shared instance for getRolloverButtonBorder(). */
+  private static Border toolbarButtonBorder;
+
+  /** The shared instance for getTextFieldBorder(). */
+  private static Border textFieldBorder;
+
+  /** The shared instance for getTextBorder(). */
+  private static Border textBorder;
+
+  /** The shared instance for getRolloverBorder(). */
+  private static Border rolloverBorder;
+
+  /**
+   * A MarginBorder that gets shared by multiple components.
+   * Created on demand by the private helper function {@link
+   * #getMarginBorder()}.
+   */
+  private static BasicBorders.MarginBorder marginBorder;
+
+  /**
+   * <p>A border used for {@link JButton} components.</p>
+   * 
+   * <p>This {@link Border} implementation can handle only instances of
+   * {@link AbstractButton} and their subclasses.</p>
+   * 
+   * <p>If the Metal Look and Feel's current theme is 'Ocean' the border
+   * will be painted with a special highlight when the mouse cursor if
+   * over the button (ie. the property <code>rollover</code> of the
+   * button's model is <code>true</code>) and is not a <b>direct</b>
+   * child of a {@link JToolBar}.</p> 
+   */
+  public static class ButtonBorder extends AbstractBorder implements UIResource
+  {
+    /** The borders insets. */
+    protected static Insets borderInsets = new Insets(3, 3, 3, 3);
+
+    /**
+     * Creates a new instance of <code>ButtonBorder</code>.
+     */
+    public ButtonBorder()
+    {
+      // Nothing to do here.
+    }
+
+    /**
+     * Paints the button border.
+     *
+     * @param c the component for which we paint the border
+     * @param g the Graphics context to use
+     * @param x the X coordinate of the upper left corner of c
+     * @param y the Y coordinate of the upper left corner of c
+     * @param w the width of c
+     * @param h the height of c
+     */
+    public void paintBorder(Component c, Graphics g, int x, int y, int w,
+                            int h)
+    {
+      // With the OceanTheme the button border is painted entirely different.
+      // However, I couldn't figure out how this is determined besides checking
+      // for instanceof OceanTheme. The button painting is definitely not
+      // influenced by a UI default property and it is definitely performed
+      // by the same Border class.
+      if (MetalLookAndFeel.getCurrentTheme() instanceof OceanTheme)
+        paintOceanButtonBorder(c, g, x, y, w, h);
+      else
+        paintDefaultButtonBorder(c, g, x, y, w, h);
+    }
+
+    /**
+     * Paints the button border for the DefaultMetalTheme.
+     *
+     * @param c the component (button)
+     * @param g the graphics object to use
+     * @param x the upper left corner of the component, X coordinate
+     * @param y the upper left corner of the component, Y coordinate
+     * @param w the width of the component
+     * @param h the height of the component
+     */
+    private void paintDefaultButtonBorder(Component c, Graphics g, int x,
+                                          int y, int w, int h)
+    {
+      ButtonModel bmodel = null;
+
+      // The RI will fail with a ClassCastException in such a situation.
+      // This code tries to be more helpful.
+      if (c instanceof AbstractButton)
+        bmodel = ((AbstractButton) c).getModel();
+      else
+        throw new IllegalStateException("A ButtonBorder is supposed to work "
+                                        + "only with AbstractButton and"
+                                        + "subclasses.");
+
+      Color darkShadow = MetalLookAndFeel.getControlDarkShadow();
+      Color shadow = MetalLookAndFeel.getControlShadow();
+      Color light = MetalLookAndFeel.getControlHighlight();
+      Color middle = MetalLookAndFeel.getControl();
+
+      if (c.isEnabled())
+        {
+          // draw dark border
+          g.setColor(darkShadow);
+          g.drawRect(x, y, w - 2, h - 2);
+
+          // If the button is the default button, we paint a special border,
+          // regardless of the pressed state.
+          if (c instanceof JButton && ((JButton) c).isDefaultButton())
+            {
+              g.drawRect(x + 1, y + 1, w - 4, h - 4);
+              // Draw white highlight.
+              g.setColor(light);
+              g.drawLine(x + 2, y + 2, x + w - 4, y + 2);
+              g.drawLine(x + 2, y + 2, x + 2, y + h - 4);
+              g.drawLine(x + 2, y + h - 1, x + w - 1, y + h - 1);
+              g.drawLine(x + w - 1, y + 2, x + w - 1, y + h - 1);
+              // Draw crossing pixels.
+              g.setColor(middle);
+              g.fillRect(x + w - 2, y + 2, 1, 1);
+              g.fillRect(x + 2, y + h - 2, 1, 1);
+            }
+          else
+            {
+              // The normal border. This is used when the button is not
+              // pressed or the button is not armed.
+              if (! (bmodel.isPressed() && bmodel.isArmed()))
+                {
+                  // draw light border
+                  g.setColor(light);
+                  g.drawRect(x + 1, y + 1, w - 2, h - 2);
+
+                  // draw crossing pixels of both borders
+                  g.setColor(middle);
+                  g.drawLine(x + 1, y + h - 2, x + 1, y + h - 2);
+                  g.drawLine(x + w - 2, y + 1, x + w - 2, y + 1);
+                }
+              // The pressed border. This border is painted only when
+              // the button is both pressed and armed.
+              else
+                {
+                  // draw light border
+                  g.setColor(light);
+                  g.drawLine(x + w - 1, y + 1, x + w - 1, y + h - 1);
+                  g.drawLine(x + 1, y + h - 1, x + w - 1, y + h - 1);
+
+                  // draw shadow border
+                  g.setColor(middle);
+                  g.drawLine(x + 1, y + 1, x + w - 2, y + 1);
+                  g.drawLine(x + 1, y + 1, x + 1, y + h - 2);
+ 
+                  // draw crossing pixels of both borders
+                  g.setColor(shadow);
+                  g.drawRect(x + 1, y + h - 2, 0, 0);
+                  g.drawRect(x + w - 2, y + 1, 0, 0);
+                }
+            }
+        }
+      else 
+        {
+          // draw disabled border
+          g.setColor(MetalLookAndFeel.getInactiveControlTextColor());
+          g.drawRect(x, y, w - 2, h - 2);          
+        }
+    }
+
+    /**
+     * Paints the button border for the OceanTheme.
+     *
+     * @param c the button
+     * @param g the graphics context
+     * @param x the X coordinate of the upper left corner of the painting rect
+     * @param y the Y coordinate of the upper left corner of the painting rect
+     * @param w the width of the painting rect
+     * @param h the height of the painting rect
+     */
+    private void paintOceanButtonBorder(Component c, Graphics g, int x,
+                                        int y, int w, int h)
+    {
+      ButtonModel bmodel = null;
+      
+      // The RI will fail with a ClassCastException in such a situation.
+      // This code tries to be more helpful.
+      if (c instanceof AbstractButton)
+        bmodel = ((AbstractButton) c).getModel();
+      else
+        throw new IllegalStateException("A ButtonBorder is supposed to work "
+                                        + "only with AbstractButton and"
+                                        + "subclasses.");
+
+      Color darkShadow = MetalLookAndFeel.getControlDarkShadow();
+      Color shadow = MetalLookAndFeel.getControlShadow();
+      Color light = MetalLookAndFeel.getControlHighlight();
+      Color middle = MetalLookAndFeel.getControl();
+
+      if (c.isEnabled())
+        {
+          // Paint the pressed border if the button is pressed, or if
+          // the button is the default button. In the OceanTheme, the default
+          // button has the same border as a pressed button.
+          if (bmodel.isPressed() || ((c instanceof JButton)
+                                     && ((JButton) c).isDefaultButton()))
+            {
+              // Draw fat border.
+              g.setColor(darkShadow);
+              g.drawRect(x, y, w - 1, h - 1);
+              g.drawRect(x + 1, y + 1, w - 3, h - 3);
+            }
+          else if (bmodel.isRollover() && !(c.getParent() instanceof JToolBar))
+            {
+              // Paint a bigger border when the mouse is over the button but
+              // only if it is *not* part of a JToolBar.
+              g.setColor(shadow);
+              g.drawRect(x, y, w - 1, h - 1);
+              g.drawRect(x + 2, y + 2, w - 5, h - 5);
+              g.setColor(darkShadow);
+              g.drawRect(x + 1, y + 1, w - 3, h - 3);
+            }
+          else
+            {
+              g.setColor(darkShadow);
+              g.drawRect(x, y, w - 1, h - 1);
+            }
+        }
+      else 
+        {
+          // draw disabled border
+          g.setColor(MetalLookAndFeel.getInactiveControlTextColor());
+          g.drawRect(x, y, w - 2, h - 2);          
+        }
+    }
+
+    /**
+     * Returns the insets of the <code>ButtonBorder</code>.
+     *
+     * @param c the component for which the border is used (ignored).
+     *
+     * @return The insets of the <code>ButtonBorder</code>.
+     */
+    public Insets getBorderInsets(Component c)
+    {
+      return borderInsets;
+    }
+
+    /**
+     * Returns the insets of the <code>ButtonBorder</code> in the specified 
+     * <code>newInsets</code> object.
+     *
+     * @param c the component for which the border is used (ignored).
+     * @param newInsets the insets object where to put the values (
+     *                  <code>null</code> not permitted).
+     *
+     * @return The <code>newInsets</code> reference.
+     */
+    public Insets getBorderInsets(Component c, Insets newInsets)
+    {
+      newInsets.bottom = borderInsets.bottom;
+      newInsets.left = borderInsets.left;
+      newInsets.right = borderInsets.right;
+      newInsets.top = borderInsets.top;
+      return newInsets;
+    }
+  }
+
+  /**
+   * A border used when painting {@link JInternalFrame} instances.
+   */
+  static class DesktopIconBorder extends AbstractBorder
+    implements UIResource
+  {
+    /**
+     * Creates a new border instance.
+     */
+    public DesktopIconBorder()
+    {
+      // Nothing to do here.
+    }
+    
+    /**
+     * Returns the border insets.
+     * 
+     * @param c  the component (ignored).
+     * 
+     * @return The border insets.
+     */
+    public Insets getBorderInsets(Component c)
+    {
+      return getBorderInsets(c, null);
+    }
+    
+    /**
+     * Returns the border insets.
+     * 
+     * @param c  the component (ignored).
+     * @return The border insets.
+     */
+    public Insets getBorderInsets(Component c, Insets newInsets)
+    {
+      if (newInsets == null)
+        newInsets = new Insets(3, 3, 2, 3);
+      else
+        {
+          newInsets.top = 3;
+          newInsets.left = 3;
+          newInsets.bottom = 2;
+          newInsets.right = 3;
+        }
+      return newInsets;  
+    }
+    
+    /**
+     * Paints the border for the specified component.
+     * 
+     * @param c  the component.
+     * @param g  the graphics device.
+     * @param x  the x-coordinate.
+     * @param y  the y-coordinate.
+     * @param w  the width.
+     * @param h  the height.
+     */
+    public void paintBorder(Component c, Graphics g, int x, int y, int w, 
+        int h)
+    {
+      g.setColor(MetalLookAndFeel.getControlDarkShadow());      
+      g.drawRect(x, y, w - 1, h - 1); 
+    }
+    
+  }
+
+  /**
+   * A simple 3D border.
+   */
+  public static class Flush3DBorder extends AbstractBorder
+    implements UIResource
+  {
+    private static final Insets borderInsets = new Insets(2, 2, 2, 2);
+    
+    /**
+     * Creates a new border instance.
+     */
+    public Flush3DBorder()
+    {
+      // Nothing to do here.
+    }
+    
+    /**
+     * Returns the border insets.
+     * 
+     * @param c  the component (ignored).
+     * 
+     * @return The border insets.
+     */
+    public Insets getBorderInsets(Component c)
+    {
+      return borderInsets;
+    }
+    
+    /**
+     * Returns the border insets.
+     * 
+     * @param c  the component (ignored).
+     * @param newInsets  an existing insets instance, that will be populated
+     *                   with the border insets and returned as the result
+     *                   (<code>null</code> not permitted).
+     *                   
+     * @return The <code>newInsets</code> reference.
+     */
+    public Insets getBorderInsets(Component c, Insets newInsets)
+    {
+      newInsets.top = borderInsets.top;
+      newInsets.left = borderInsets.left;
+      newInsets.bottom = borderInsets.bottom;
+      newInsets.right = borderInsets.right;
+      return newInsets;  
+    }
+    
+    /**
+     * Paints the border for the specified component.
+     * 
+     * @param c  the component (ignored).
+     * @param g  the graphics device.
+     * @param x  the x-coordinate.
+     * @param y  the y-coordinate.
+     * @param w  the width.
+     * @param h  the height.
+     */
+    public void paintBorder(Component c, Graphics g, int x, int y, int w, 
+        int h)
+    {              
+      Color savedColor = g.getColor();
+      g.setColor(MetalLookAndFeel.getControlDarkShadow());
+      g.drawRect(x, y, w - 2, h - 2);
+      g.setColor(MetalLookAndFeel.getControlHighlight());
+      g.drawRect(x + 1, y + 1, w - 2, h - 2);
+      g.setColor(MetalLookAndFeel.getControl());
+      g.drawLine(x + 1, y + h - 2, x + 1, y + h - 2);
+      g.drawLine(x + w - 2, y + 1, x + w - 2, y + 1);
+      g.setColor(savedColor);
+    }
+    
+  }
+    
+  /**
+   * A border used for a {@link JInternalFrame} when it is being used as a 
+   * palette.
+   * 
+   * @since 1.3
+   */
+  public static class PaletteBorder extends AbstractBorder
+    implements UIResource
+  {
+    private static final Insets borderInsets = new Insets(1, 1, 1, 1);
+
+    /**
+     * Creates a new <code>PaletteBorder</code>.
+     */
+    public PaletteBorder()
+    {
+      // Nothing to do here.
+    }
+    
+    /**
+     * Returns the border insets.
+     * 
+     * @param c  the component (ignored).
+     * 
+     * @return The border insets.
+     */
+    public Insets getBorderInsets(Component c)
+    {
+      return borderInsets;
+    }
+
+    /**
+     * Returns the border insets.
+     * 
+     * @param c  the component (ignored).
+     * @param newInsets  an existing insets instance, that will be populated
+     *                   with the border insets and returned as the result
+     *                   (<code>null</code> not permitted).
+     *                   
+     * @return The <code>newInsets</code> reference.
+     */
+    public Insets getBorderInsets(Component c, Insets newInsets)
+    {        
+      newInsets.top = borderInsets.top;
+      newInsets.left = borderInsets.left;
+      newInsets.bottom = borderInsets.bottom;
+      newInsets.right = borderInsets.right;
+      return newInsets;  
+    }
+    
+    /**
+     * Paints the border for the specified component.
+     * 
+     * @param c  the component (ignored).
+     * @param g  the graphics device.
+     * @param x  the x-coordinate.
+     * @param y  the y-coordinate.
+     * @param w  the width.
+     * @param h  the height.
+     */
+    public void paintBorder(Component c, Graphics g, int x, int y, int w, 
+            int h)
+    {
+      Color savedColor = g.getColor();
+      
+      // draw the outline
+      g.setColor(MetalLookAndFeel.getPrimaryControlDarkShadow());
+      g.drawRect(x, y, w - 1, h - 1);
+      
+      // put a dot in each corner
+      g.setColor(MetalLookAndFeel.getControl());
+      g.fillRect(x, y, 1, 1);
+      g.fillRect(x + w - 1, y, 1, 1);
+      g.fillRect(x + w - 1, y + h - 1, 1, 1);
+      g.fillRect(x, y + h - 1, 1, 1);      
+      g.setColor(savedColor);
+    }
+
+  }
+    
+  /**
+   * A border used for the {@link JTextField} component.
+   */
+  public static class TextFieldBorder extends Flush3DBorder
+    implements UIResource
+  {
+    /**
+     * Creates a new border instance.
+     */
+    public TextFieldBorder()
+    {
+      // Nothing to do here.
+    }
+    
+    /**
+     * Paints the border for the specified component.
+     * 
+     * @param c  the component (ignored).
+     * @param g  the graphics device.
+     * @param x  the x-coordinate.
+     * @param y  the y-coordinate.
+     * @param w  the width.
+     * @param h  the height.
+     */
+    public void paintBorder(Component c, Graphics g, int x, int y, int w, 
+        int h)
+    {
+      boolean enabledTextBorder;
+      if (c instanceof JTextComponent)
+        {
+          JTextComponent tc = (JTextComponent) c;
+          enabledTextBorder = tc.isEnabled() && tc.isEditable();
+        }
+      else
+        enabledTextBorder = false;
+
+      if (enabledTextBorder)
+        super.paintBorder(c, g, x, y, w, h);
+      else
+        {
+          Color savedColor = g.getColor();
+          g.setColor(MetalLookAndFeel.getControlShadow());
+          g.drawRect(x, y, w - 1, h - 1);
+          g.setColor(savedColor);
+        }
+    }
+    
+  }
+
+  /**
+   * A border used for the {@link JInternalFrame} component.
+   */
+  public static class InternalFrameBorder extends AbstractBorder
+    implements UIResource
+  {
+    private static final Insets borderInsets = new Insets(5, 5, 5, 5);
+
+    /**
+     * Creates a new border instance.
+     */
+    public InternalFrameBorder()
+    {
+      // Nothing to do here.
+    }
+    
+    /**
+     * Returns the border insets.
+     * 
+     * @param c  the component (ignored).
+     * 
+     * @return The border insets.
+     */
+    public Insets getBorderInsets(Component c)
+    {
+      return borderInsets;
+    }
+    
+    /**
+     * Returns the border insets.
+     * 
+     * @param c  the component (ignored).
+     * @param newInsets  an existing insets instance, that will be populated
+     *                   with the border insets and returned as the result
+     *                   (<code>null</code> not permitted).
+     *                   
+     * @return The <code>newInsets</code> reference.
+     */
+    public Insets getBorderInsets(Component c, Insets newInsets)
+    {
+      newInsets.top = borderInsets.top;
+      newInsets.left = borderInsets.left;
+      newInsets.bottom = borderInsets.bottom;
+      newInsets.right = borderInsets.right;
+      return newInsets;  
+    }
+    
+    /**
+     * Paints the border for the specified component.
+     * 
+     * @param c  the component.
+     * @param g  the graphics device.
+     * @param x  the x-coordinate.
+     * @param y  the y-coordinate.
+     * @param w  the width.
+     * @param h  the height.
+     */
+    public void paintBorder(Component c, Graphics g, int x, int y, int w, 
+        int h)
+    {
+        
+      JInternalFrame f = (JInternalFrame) c;
+      if (f.isSelected())
+        g.setColor(MetalLookAndFeel.getPrimaryControlDarkShadow());
+      else
+        g.setColor(MetalLookAndFeel.getControlDarkShadow());
+      
+      // fill the border background
+      g.fillRect(x, y, w, 5);
+      g.fillRect(x, y, 5, h);
+      g.fillRect(x + w - 5, y, 5, h);
+      g.fillRect(x, y + h - 5, w, 5);
+      
+      // draw a dot in each corner
+      g.setColor(MetalLookAndFeel.getControl());
+      g.fillRect(x, y, 1, 1);
+      g.fillRect(x + w - 1, y, 1, 1);
+      g.fillRect(x + w - 1, y + h - 1, 1, 1);
+      g.fillRect(x, y + h - 1, 1, 1);
+      
+      // draw the lines
+      g.setColor(MetalLookAndFeel.getBlack());
+      g.drawLine(x + 14, y + 2, x + w - 15, y + 2);
+      g.drawLine(x + 14, y + h - 3, x + w - 15, y + h - 3);
+      g.drawLine(x + 2, y + 14, x + 2, y + h - 15);
+      g.drawLine(x + w - 3, y + 14, x + w - 3, y + h - 15);
+      
+      // draw the line highlights
+      if (f.isSelected())
+        g.setColor(MetalLookAndFeel.getPrimaryControlShadow());
+      else 
+        g.setColor(MetalLookAndFeel.getControlShadow());
+      g.drawLine(x + 15, y + 3, x + w - 14, y + 3);
+      g.drawLine(x + 15, y + h - 2, x + w - 14, y + h - 2);
+      g.drawLine(x + 3, y + 15, x + 3, y + h - 14);
+      g.drawLine(x + w - 2, y + 15, x + w - 2, y + h - 14);
+    }
+    
+  }
+
+  /**
+   * A border used for {@link JInternalFrame} components that are
+   * presented as dialogs (by the {@link JOptionPane} class).
+   */
+  public static class OptionDialogBorder extends AbstractBorder
+    implements UIResource
+  {
+      
+    /**
+     * Creates a new border instance.
+     */
+    public OptionDialogBorder()
+    {
+      // Nothing to do here.
+    }
+    
+    /**
+     * Returns the border insets.
+     * 
+     * @param c  the component (ignored).
+     * 
+     * @return The border insets.
+     */
+    public Insets getBorderInsets(Component c)
+    {
+      return getBorderInsets(c, null);
+    }
+    
+    /**
+     * Returns the border insets.
+     * 
+     * @param c  the component (ignored).
+     * @return The border insets.
+     */
+    public Insets getBorderInsets(Component c, Insets newInsets)
+    {
+      if (newInsets == null)
+        newInsets = new Insets(3, 3, 3, 3);
+      else
+        {
+          newInsets.top = 3;
+          newInsets.left = 3;
+          newInsets.bottom = 3;
+          newInsets.right = 3;
+        }
+      return newInsets;  
+    }
+        
+    /**
+     * Paints the border for the specified component.
+     * 
+     * @param c  the component.
+     * @param g  the graphics device.
+     * @param x  the x-coordinate.
+     * @param y  the y-coordinate.
+     * @param w  the width.
+     * @param h  the height.
+     */
+    public void paintBorder(Component c, Graphics g, int x, int y, int w, 
+        int h)
+    {
+        
+      JInternalFrame f = (JInternalFrame) c;
+      g.setColor(MetalLookAndFeel.getPrimaryControlDarkShadow());
+      if (f.getContentPane() instanceof JOptionPane)
+        {
+          JOptionPane pane = (JOptionPane) f.getContentPane();
+          int type = pane.getMessageType();
+          if (type == JOptionPane.QUESTION_MESSAGE)
+            {
+              Color bc = UIManager.getColor(
+                  "OptionPane.questionDialog.border.background");
+              if (bc != null)
+                g.setColor(bc);
+            }
+          if (type == JOptionPane.WARNING_MESSAGE)
+            {
+              Color bc = UIManager.getColor(
+                  "OptionPane.warningDialog.border.background");
+              if (bc != null)
+                g.setColor(bc);              
+            }
+          else if (type == JOptionPane.ERROR_MESSAGE)
+            {
+              Color bc = UIManager.getColor(
+                  "OptionPane.errorDialog.border.background");
+              if (bc != null)
+                g.setColor(bc);              
+            }
+        }
+      
+      // fill the border background
+      g.fillRect(x, y, w, 3);
+      g.fillRect(x, y, 3, h);
+      g.fillRect(x + w - 3, y, 3, h);
+      g.fillRect(x, y + h - 3, w, 3);
+      
+      // draw a dot in each corner
+      g.setColor(MetalLookAndFeel.getControl());
+      g.fillRect(x, y, 1, 1);
+      g.fillRect(x + w - 1, y, 1, 1);
+      g.fillRect(x + w - 1, y + h - 1, 1, 1);
+      g.fillRect(x, y + h - 1, 1, 1);
+      
+    }
+    
+  }
+
+  /**
+   * A border used for {@link JMenu} and {@link JMenuItem} components.
+   */
+  public static class MenuItemBorder extends AbstractBorder
+    implements UIResource
+  {
+    /** The border insets. */
+    protected static Insets borderInsets = new Insets(2, 2, 2, 2);
+    
+    /**
+     * Creates a new border instance.
+     */
+    public MenuItemBorder()
+    {
+      // Nothing to do here.
+    }
+    
+    /**
+     * Paints the border for the component.  A border is painted only if the
+     * component is a selected {@link JMenu} or an armed {@link JMenuItem}.
+     * 
+     * @param c  the component.
+     * @param g  the graphics device.
+     * @param x  the x-coordinate of the border area.
+     * @param y  the y-coordinate of the border area.
+     * @param w  the width of the border area.
+     * @param h  the height of the border area.
+     */
+    public void paintBorder(Component c, Graphics g, int x, int y, int w,
+        int h)
+    {
+      Color dark = MetalLookAndFeel.getPrimaryControlDarkShadow();
+      Color light = MetalLookAndFeel.getPrimaryControlHighlight();
+      if (c instanceof JMenu) 
+        {
+          JMenu menu = (JMenu) c;
+          if (menu.isSelected())
+            {
+              g.setColor(dark);
+              g.drawLine(x, y, x, y + h);
+              g.drawLine(x, y, x + w, y);
+              g.drawLine(x + w - 2, y + 1, x + w - 2, y + h);
+              g.setColor(light);
+              g.drawLine(x + w - 1, y + 1, x + w - 1, y + h);
+            }
+        }
+      else if (c instanceof JMenuItem)
+        {
+          JMenuItem item = (JMenuItem) c;
+          if (item.isArmed()) 
+            {
+              g.setColor(dark);
+              g.drawLine(x, y, x + w, y);
+              g.setColor(light);
+              g.drawLine(x, y + h - 1, x + w, y + h - 1);
+            }
+          else
+            {
+              // Normally we draw a light line on the left.
+              g.setColor(light);
+              g.drawLine(x, y, x, y + h);
+            }
+        }
+    }
+    
+    /**
+     * Returns the border insets.
+     * 
+     * @param c  the component (ignored).
+     * 
+     * @return The border insets.
+     */
+    public Insets getBorderInsets(Component c)
+    {
+      return borderInsets;
+    }
+    
+    /**
+     * Populates <code>insets</code> with the border insets, then returns it.
+     * 
+     * @param c  the component (ignored).
+     * @param insets  the object to populate with the border insets.
+     * 
+     * @return The border insets.
+     * 
+     * @throws NullPointerException if <code>insets</code> is <code>null</code>.
+     */
+    public Insets getBorderInsets(Component c, Insets insets)
+    {
+      insets.left = borderInsets.left;
+      insets.top = borderInsets.top;
+      insets.bottom = borderInsets.bottom;
+      insets.right = borderInsets.right;
+      return insets;
+    }
+  }
+
+  /**
+   * A border used for {@link JMenuBar} components.
+   */
+  public static class MenuBarBorder
+      extends AbstractBorder
+      implements UIResource
+  {
+    /** The border insets. */
+    protected static Insets borderInsets = new Insets(1, 0, 1, 0);
+    
+    // TODO: find where this color really comes from
+    private static Color borderColor = new Color(153, 153, 153);
+    
+    /**
+     * Creates a new border instance.
+     */
+    public MenuBarBorder()
+    {
+      // Nothing to do here.
+    }
+    
+    /**
+     * Paints the border for the component.  A border is painted only if the
+     * component is a selected {@link JMenu} or an armed {@link JMenuItem}.
+     * 
+     * @param c  the component.
+     * @param g  the graphics device.
+     * @param x  the x-coordinate of the border area.
+     * @param y  the y-coordinate of the border area.
+     * @param w  the width of the border area.
+     * @param h  the height of the border area.
+     */
+    public void paintBorder(Component c, Graphics g, int x, int y, int w,
+        int h)
+    {
+      g.setColor(borderColor);
+      g.drawLine(x, y + h - 1, x + w, y + h - 1);
+    }
+    
+    /**
+     * Returns the border insets.
+     * 
+     * @param c  the component (ignored).
+     * 
+     * @return The border insets.
+     */
+    public Insets getBorderInsets(Component c)
+    {
+      return borderInsets;
+    }
+    
+    /**
+     * Populates <code>insets</code> with the border insets, then returns it.
+     * 
+     * @param c  the component (ignored).
+     * @param insets  the object to populate with the border insets.
+     * 
+     * @return The border insets.
+     * 
+     * @throws NullPointerException if <code>insets</code> is <code>null</code>.
+     */
+    public Insets getBorderInsets(Component c, Insets insets)
+    {
+      insets.left = borderInsets.left;
+      insets.top = borderInsets.top;
+      insets.bottom = borderInsets.bottom;
+      insets.right = borderInsets.right;
+      return insets;
+    }
+  }
+
+  /**
+   * A border for {@link JScrollPane} components.
+   */
+  public static class ScrollPaneBorder
+    extends AbstractBorder
+    implements UIResource
+  {
+    /** The border insets. */
+    private static Insets insets = new Insets(1, 1, 2, 2);
+    
+    /**
+     * Constructs a new ScrollPaneBorder.
+     */
+    public ScrollPaneBorder()
+    {
+      // Nothing to do here.
+    }
+    
+    /**
+     * Returns the insets of the border for the Component <code>c</code>.
+     *
+     * @param c the Component for which we return the border insets
+     */
+    public Insets getBorderInsets(Component c)
+    {
+      return insets;
+    }
+
+    /**
+     * Paints the border.
+     *
+     * @param c the Component for which the border is painted
+     * @param g the Graphics context
+     * @param x the X coordinate of the upper left corner of the border
+     * @param y the Y coordinate of the upper left corner of the border
+     * @param w the width of the border
+     * @param h the height of the border
+     */
+    public void paintBorder(Component c, Graphics g, int x, int y,
+                            int w, int h)
+    {
+      Color darkShadow = MetalLookAndFeel.getControlDarkShadow();
+      Color shadow = MetalLookAndFeel.getControlShadow();
+      Color light = MetalLookAndFeel.getWhite();
+      Color middle = MetalLookAndFeel.getControl();
+
+      // paint top border line
+      g.setColor(darkShadow);
+      g.drawLine(x, y, x + w - 2, y);
+
+      // paint left border line
+      g.drawLine(x, y, x, y + h - 2);
+ 
+      // paint right inner border line
+      g.drawLine(x + w - 2, y, x + w - 2, y + h + 1);
+
+      // paint bottom inner border line
+      g.drawLine(x + 2, y + h - 2, x + w - 2, y + h - 2);
+
+      // draw right outer border line
+      g.setColor(light);
+      g.drawLine(x + w - 1, y, x + w - 1, y + h - 1);
+
+      // draw bottom outer border line
+      g.drawLine(x, y + h - 1, x + w - 1, y + h - 1);
+
+      // paint the lighter points
+      g.setColor(middle);
+      g.drawLine(x + w - 1, y, x + w - 1, y);
+      g.drawLine(x + w - 2, y + 2, x + w - 2, y + 2);
+      g.drawLine(x, y + h - 1, x, y + h - 1);
+      g.drawLine(x + 1, y + h - 2, x + 1, y + h - 2);
+
+    }
+    
+  }
+  
+  /**
+   * A button border that is only visible when the mouse pointer is within 
+   * the button's bounds.
+   */
+  public static class RolloverButtonBorder
+    extends MetalBorders.ButtonBorder
+  {
+    /**
+     * Creates a new border instance.
+     */
+    public RolloverButtonBorder()
+    {
+      // Nothing to do here.
+    }
+    
+    /**
+     * Paints the border.
+     * 
+     * @param c  the component.
+     * @param g  the graphics device.
+     * @param x  the x-coordinate.
+     * @param y  the y-coordinate.
+     * @param w  the width.
+     * @param h  the height.
+     */
+    public void paintBorder(Component c, Graphics g, int x, int y, int w, 
+            int h)
+    {
+      // TODO: What should be done here? Obviously the ButtonBorder already
+      // handles the rollover state in Sun's impl. Maybe this is only there
+      // for backwards compatibility.
+      super.paintBorder(c, g, x, y, w, h);
+    }
+  }
+  
+  /**
+   * This border is used in Toolbar buttons as inner border.
+   */
+  static class RolloverMarginBorder extends AbstractBorder
+  {
+    /** The borders insets. */
+    protected static Insets borderInsets = new Insets(3, 3, 3, 3);
+
+    /**
+     * Creates a new instance of RolloverBorder.
+     */
+    public RolloverMarginBorder()
+    {
+      // Nothing to do here.
+    }
+    
+    /**
+     * Returns the insets of the RolloverBorder.
+     *
+     * @param c the component for which the border is used
+     *
+     * @return the insets of the RolloverBorder
+     */
+    public Insets getBorderInsets(Component c)
+    {
+      return getBorderInsets(c, null);
+    }
+
+    /**
+     * Returns the insets of the RolloverMarginBorder in the specified
+     * Insets object.
+     *
+     * @param c the component for which the border is used
+     * @param newInsets the insets object where to put the values
+     *
+     * @return the insets of the RolloverMarginBorder
+     */
+    public Insets getBorderInsets(Component c, Insets newInsets)
+    {
+      if (newInsets == null)
+        newInsets = new Insets(0, 0, 0, 0);
+
+      AbstractButton b = (AbstractButton) c;
+      Insets margin = b.getMargin();
+      newInsets.bottom = borderInsets.bottom;
+      newInsets.left = borderInsets.left;
+      newInsets.right = borderInsets.right;
+      newInsets.top = borderInsets.top;
+      return newInsets;
+    }
+  }
+
+  /**
+   * A border implementation for popup menus.
+   */
+  public static class PopupMenuBorder
+    extends AbstractBorder
+    implements UIResource
+  {
+
+    /** The border's insets. */
+    protected static Insets borderInsets = new Insets(3, 1, 2, 1);
+
+    /**
+     * Constructs a new PopupMenuBorder.
+     */
+    public PopupMenuBorder()
+    {
+      // Nothing to do here.
+    }
+    
+    /**
+     * Returns the insets of the border, creating a new Insets instance
+     * with each call.
+     *
+     * @param c the component for which we return the border insets
+     *          (not used here)
+     */
+    public Insets getBorderInsets(Component c)
+    {
+      return getBorderInsets(c, null);
+    }
+    
+    /**
+     * Returns the insets of the border, using the supplied Insets instance.
+     *
+     * @param c the component for which we return the border insets
+     *          (not used here)
+     * @param i the Insets instance to fill with the Insets values
+     */
+    public Insets getBorderInsets(Component c, Insets i)
+    {
+      Insets insets;
+      if (i == null)
+        insets = new Insets(borderInsets.top, borderInsets.left,
+                            borderInsets.bottom, borderInsets.right);
+      else
+        {
+          insets = i;
+          insets.top = borderInsets.top;
+          insets.left = borderInsets.left;
+          insets.bottom = borderInsets.bottom;
+          insets.right = borderInsets.right;
+        }
+      
+      return insets;
+    }
+
+    /**
+     * Paints the border for component <code>c</code> using the
+     * Graphics context <code>g</code> with the dimension
+     * <code>x, y, w, h</code>.
+     *
+     * @param c the component for which we paint the border
+     * @param g the Graphics context to use
+     * @param x the X coordinate of the upper left corner of c
+     * @param y the Y coordinate of the upper left corner of c
+     * @param w the width of c
+     * @param h the height of c
+     */
+    public void paintBorder(Component c, Graphics g, int x, int y, int w,
+                            int h)
+    {
+      Color darkShadow = MetalLookAndFeel.getPrimaryControlDarkShadow();
+      Color light = MetalLookAndFeel.getPrimaryControlHighlight();
+
+      // draw dark outer border
+      g.setColor(darkShadow);
+      g.drawRect(x, y, w - 1, h - 1);
+      
+      // draw highlighted inner border (only top and left)
+      g.setColor(light);
+      g.drawLine(x + 1, y + 1, x + w - 2, y + 1);
+    }
+    
+  }
+
+  /**
+   * A border used for the {@link JToggleButton} component.
+   * 
+   * @since 1.3
+   */
+  public static class ToggleButtonBorder
+    extends ButtonBorder 
+  {
+    /**
+     * Creates a new border instance.
+     */
+    public ToggleButtonBorder()
+    {
+      // Nothing to do here.
+    }
+    
+    /**
+     * Paints the toggle button border.
+     *
+     * @param c the component for which we paint the border
+     * @param g the Graphics context to use
+     * @param x the X coordinate of the upper left corner of c
+     * @param y the Y coordinate of the upper left corner of c
+     * @param w the width of c
+     * @param h the height of c
+     */
+    public void paintBorder(Component c, Graphics g, int x, int y, int w,
+                            int h)
+    {
+      ButtonModel bmodel = null;
+      
+      if (c instanceof AbstractButton)
+        bmodel = ((AbstractButton) c).getModel();
+
+      Color darkShadow = MetalLookAndFeel.getControlDarkShadow();
+      Color shadow = MetalLookAndFeel.getControlShadow();
+      Color light = MetalLookAndFeel.getWhite();
+      Color middle = MetalLookAndFeel.getControl();
+
+      if (c.isEnabled())
+        {
+          // draw dark border
+          g.setColor(darkShadow);
+          g.drawRect(x, y, w - 2, h - 2);
+
+          if (!bmodel.isArmed())
+            {
+              // draw light border
+              g.setColor(light);
+              g.drawLine(x + 1, y + h - 1, x + w - 1, y + h - 1);
+              g.drawLine(x + w - 1, y + 1, x + w - 1, y + h - 1);
+              if (bmodel.isSelected())
+                g.setColor(middle);
+              g.drawLine(x + 1, y + 1, x + w - 3, y + 1);
+              g.drawLine(x + 1, y + 1, x + 1, y + h - 3);
+
+              // draw crossing pixels of both borders
+              g.setColor(shadow);
+              g.drawLine(x + 1, y + h - 2, x + 1, y + h - 2);
+              g.drawLine(x + w - 2, y + 1, x + w - 2, y + 1);
+            }
+          else
+            {
+              // draw light border
+              g.setColor(light);
+              g.drawLine(x + w - 1, y + 1, x + w - 1, y + h - 1);
+              g.drawLine(x + 1, y + h - 1, x + w - 1, y + h - 1);
+
+              // draw shadow border
+              g.setColor(shadow);
+              g.drawLine(x + 1, y + 1, x + w - 2, y + 1);
+              g.drawLine(x + 1, y + 1, x + 1, y + h - 2);
+ 
+              // draw crossing pixels of both borders
+              g.setColor(shadow);
+              g.drawLine(x + 1, y + h - 2, x + 1, y + h - 2);
+              g.drawLine(x + w - 2, y + 1, x + w - 2, y + 1);
+              
+            }
+          // draw corners
+          g.setColor(middle);
+          g.drawLine(x, y + h - 1, x, y + h - 1);
+          g.drawLine(x + w - 1, y, x + w - 1, y);
+        }
+      else 
+        {
+          // draw disabled border
+          g.setColor(MetalLookAndFeel.getControlDisabled());
+          g.drawRect(x, y, w - 2, h - 2);          
+        }
+    }
+  }
+
+  /**
+   * A border used for the {@link JToolBar} component.
+   */
+  public static class ToolBarBorder extends AbstractBorder
+    implements UIResource, SwingConstants
+  {
+    /**
+     * Creates a new border instance.
+     */
+    public ToolBarBorder()
+    {
+      // Nothing to do here.
+    }
+    
+    /**
+     * Returns the border insets.
+     * 
+     * @param c  the component (ignored).
+     * 
+     * @return The border insets.
+     */
+    public Insets getBorderInsets(Component c)
+    {
+      return getBorderInsets(c, null);
+    }
+    
+    /**
+     * Returns the border insets.
+     * 
+     * @param c  the component (ignored).
+     * @return The border insets.
+     */
+    public Insets getBorderInsets(Component c, Insets newInsets)
+    {
+      JToolBar tb = (JToolBar) c;
+      if (tb.getOrientation() == JToolBar.HORIZONTAL)
+        {   
+          if (newInsets == null)
+            newInsets = new Insets(2, 16, 2, 2);
+          else
+            {
+              newInsets.top = 2;
+              newInsets.left = 16;
+              newInsets.bottom = 2;
+              newInsets.right = 2;
+            }
+          return newInsets;  
+        }
+      else // assume JToolBar.VERTICAL
+        { 
+          if (newInsets == null)
+            newInsets = new Insets(16, 2, 2, 2);
+          else
+            {
+              newInsets.top = 16;
+              newInsets.left = 2;
+              newInsets.bottom = 2;
+              newInsets.right = 2;
+            }
+          return newInsets;  
+        }
+
+    }
+    
+    /**
+     * Paints the border for the specified component.
+     * 
+     * @param c  the component.
+     * @param g  the graphics device.
+     * @param x  the x-coordinate.
+     * @param y  the y-coordinate.
+     * @param w  the width.
+     * @param h  the height.
+     */
+    public void paintBorder(Component c, Graphics g, int x, int y, int w, 
+        int h)
+    {
+        
+      JToolBar tb = (JToolBar) c;
+      if (tb.getOrientation() == JToolBar.HORIZONTAL)
+        {
+           MetalUtils.fillMetalPattern(tb, g, x + 2, y + 2, x + 11, y + h - 5, 
+                  MetalLookAndFeel.getControlHighlight(), 
+                  MetalLookAndFeel.getControlDarkShadow());
+        }
+      else
+        { 
+          MetalUtils.fillMetalPattern(tb, g, x + 2, y + 2, x + w - 5, y + 11, 
+                  MetalLookAndFeel.getControlHighlight(), 
+                  MetalLookAndFeel.getControlDarkShadow());
+        }
+    }
+    
+  }
+  
+  /**
+   * A border for table header cells.
+   *
+   * @since 1.3
+   */
+  public static class TableHeaderBorder extends AbstractBorder
+  {
+    /**
+     * The insets of this border.
+     */
+    // TODO: According to tests that I have done, this is really the border
+    // that should be returned by getBorderInsets(). However, the name
+    // is very distracting. Is there any deeper meaning in it?
+    protected Insets editorBorderInsets;
+
+    /**
+     * Creates a new instance of <code>TableHeaderBorder</code>.
+     */
+    public TableHeaderBorder()
+    {
+      editorBorderInsets = new Insets(1, 1, 1, 1);
+    }
+
+    /**
+     * Return the insets of this border.
+     *
+     * @return the insets of this border
+     */
+    public Insets getBorderInsets(Component c)
+    {
+      return editorBorderInsets;
+    }
+
+    /**
+     * Paints the border.
+     *
+     * @param c the component for which to paint the border
+     * @param g the graphics context to use
+     * @param x the x cooridinate of the border rectangle
+     * @param y the y cooridinate of the border rectangle
+     * @param w the width of the border rectangle
+     * @param h the height of the border rectangle
+     */
+    public void paintBorder(Component c, Graphics g, int x, int y, int w, int h)
+    {
+      Color dark = MetalLookAndFeel.getControlDarkShadow();
+      Color light = MetalLookAndFeel.getWhite();
+      Color old = g.getColor();
+      g.setColor(light);
+      g.drawLine(x, y, x + w - 2, y);
+      g.drawLine(x, y, x, y + h - 2);
+      g.setColor(dark);
+      g.drawLine(x + w - 1, y, x + w - 1, y + h - 1);
+      g.drawLine(x + 1, y + h - 1, x + w - 1, y + h - 1);
+      g.setColor(old);
+    }
+  }
+
+  /**
+   * Returns a border for Swing buttons in the Metal Look & Feel.
+   *
+   * @return a border for Swing buttons in the Metal Look & Feel
+   */
+  public static Border getButtonBorder()
+  {
+    if (buttonBorder == null)
+      {
+        Border outer = new ButtonBorder();
+        Border inner = getMarginBorder();
+        buttonBorder = new BorderUIResource.CompoundBorderUIResource(outer, 
+            inner);
+      }
+    return buttonBorder;
+  }
+  
+  /**
+   * Returns a border for use with {@link JToggleButton} components.
+   *
+   * @return A border.
+   * 
+   * @since 1.3
+   */
+  public static Border getToggleButtonBorder()
+  {
+    if (toggleButtonBorder == null)
+      {
+        Border outer = new ToggleButtonBorder();
+        Border inner = getMarginBorder();
+        toggleButtonBorder = new BorderUIResource.CompoundBorderUIResource(
+            outer, inner);
+      }
+    return toggleButtonBorder;
+  }
+
+  /**
+   * Returns a border instance that is used with a {@link JInternalFrame} when
+   * it is in the iconified state.
+   * 
+   * @return A border.
+   * 
+   * @since 1.3
+   */
+  public static Border getDesktopIconBorder()
+  {
+    if (desktopIconBorder == null)
+      desktopIconBorder = new DesktopIconBorder();
+    return desktopIconBorder;      
+  }
+
+  /**
+   * Returns a border for use by the {@link JTextField} component.
+   * 
+   * @return A border.
+   * 
+   * @since 1.3
+   */
+  public static Border getTextFieldBorder()
+  {
+    if (textFieldBorder == null)
+      {
+        Border inner = getMarginBorder();
+        Border outer = new TextFieldBorder();
+        textFieldBorder =
+          new BorderUIResource.CompoundBorderUIResource(outer, inner);
+      }
+    return textFieldBorder;
+  }
+
+  /**
+   * Returns the border that is used for text components (except text fields,
+   * which use {@link #getTextFieldBorder}.
+   *
+   * @return the border that is used for text components
+   *
+   * @since 1.3
+   */
+  public static Border getTextBorder()
+  {
+    if (textBorder == null)
+      {
+        Border inner = getMarginBorder();
+        Border outer = new Flush3DBorder();
+        textBorder =
+          new BorderUIResource.CompoundBorderUIResource(outer, inner);
+      }
+    return textBorder;
+  }
+
+  /**
+   * Returns a border for Toolbar buttons in the Metal Look & Feel.
+   *
+   * @return a border for Toolbar buttons in the Metal Look & Feel
+   */
+  static Border getToolbarButtonBorder()
+  {
+    if (toolbarButtonBorder == null)
+      {
+        Border outer = new ButtonBorder();
+        Border inner = new RolloverMarginBorder();
+        toolbarButtonBorder = new CompoundBorder(outer, inner);
+      }
+    return toolbarButtonBorder;
+  }
+
+  /**
+   * Returns a shared instance of {@link BasicBorders.MarginBorder}.
+   *
+   * @return a shared instance of {@link BasicBorders.MarginBorder}
+   */
+  static Border getMarginBorder()
+  {
+    if (marginBorder == null)
+      marginBorder = new BasicBorders.MarginBorder();
+    return marginBorder;
+  }
+
+  /**
+   * Returns a shared instance of a compound border for rollover buttons.
+   * 
+   * @return A shared border instance.
+   */
+  static Border getRolloverBorder()
+  {
+    if (rolloverBorder == null)
+      {
+        Border outer = new MetalBorders.RolloverButtonBorder();
+        Border inner = MetalBorders.getMarginBorder();
+        rolloverBorder = new BorderUIResource.CompoundBorderUIResource(outer, 
+            inner);
+      }
+    return rolloverBorder;
+  }
+
+}

Added: llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/metal/MetalButtonListener.java
URL: http://llvm.org/viewvc/llvm-project/llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/metal/MetalButtonListener.java?rev=43913&view=auto

==============================================================================
--- llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/metal/MetalButtonListener.java (added)
+++ llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/metal/MetalButtonListener.java Thu Nov  8 16:56:19 2007
@@ -0,0 +1,74 @@
+/* MetalButtonListener.java
+   Copyright (C) 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package javax.swing.plaf.metal;
+
+import java.beans.PropertyChangeEvent;
+
+import javax.swing.AbstractButton;
+import javax.swing.plaf.basic.BasicButtonListener;
+
+/**
+ * A listener for buttons under the {@link MetalLookAndFeel}.
+ * 
+ * @see MetalButtonUI#createButtonListener
+ */
+class MetalButtonListener extends BasicButtonListener 
+{
+  
+  /**
+   * Creates a new instance.
+   * 
+   * @param button  the button.
+   */
+  public MetalButtonListener(AbstractButton button)
+  {
+    super(button);
+  }
+  
+  /**
+   * Handles property change events.
+   * 
+   * @param e  the event.
+   */
+  public void propertyChange(PropertyChangeEvent e)
+  {
+    super.propertyChange(e);
+    // TODO: What should be done here?
+  }
+}

Added: llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/metal/MetalButtonUI.java
URL: http://llvm.org/viewvc/llvm-project/llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/metal/MetalButtonUI.java?rev=43913&view=auto

==============================================================================
--- llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/metal/MetalButtonUI.java (added)
+++ llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/metal/MetalButtonUI.java Thu Nov  8 16:56:19 2007
@@ -0,0 +1,299 @@
+/* MetalButtonUI.java
+   Copyright (C) 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package javax.swing.plaf.metal;
+
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Font;
+import java.awt.FontMetrics;
+import java.awt.Graphics;
+import java.awt.Rectangle;
+
+import javax.swing.AbstractButton;
+import javax.swing.ButtonModel;
+import javax.swing.JButton;
+import javax.swing.JComponent;
+import javax.swing.JToolBar;
+import javax.swing.SwingConstants;
+import javax.swing.UIManager;
+import javax.swing.plaf.ComponentUI;
+import javax.swing.plaf.UIResource;
+import javax.swing.plaf.basic.BasicButtonListener;
+import javax.swing.plaf.basic.BasicButtonUI;
+
+/**
+ * A UI delegate for the {@link JButton} component.
+ *
+ * @author Roman Kennke (roman at kennke.org)
+ */
+public class MetalButtonUI
+  extends BasicButtonUI
+{
+
+  /** The color used to draw the focus rectangle around the text and/or icon. */
+  protected Color focusColor;
+    
+  /** The background color for the button when it is pressed. */
+  protected Color selectColor;
+
+  /** The color for disabled button labels. */
+  protected Color disabledTextColor;
+
+  /**
+   * Creates a new instance.
+   */
+  public MetalButtonUI()
+  {
+    super();
+    focusColor = UIManager.getColor(getPropertyPrefix() + "focus");
+    selectColor = UIManager.getColor(getPropertyPrefix() + "select");
+    disabledTextColor = UIManager.getColor(getPropertyPrefix() + "disabledText");
+  }
+
+  /**
+   * Returns the color for the focus border.
+   *
+   * @return the color for the focus border
+   */
+  protected Color getFocusColor()
+  {
+    return focusColor;
+  }
+
+  /**
+   * Returns the color that indicates a selected button.
+   *
+   * @return the color that indicates a selected button
+   */
+  protected Color getSelectColor()
+  {
+    return selectColor;
+  }
+
+  /**
+   * Returns the color for the text label of disabled buttons.
+   *
+   * @return the color for the text label of disabled buttons
+   */
+  protected Color getDisabledTextColor()
+  {
+    return disabledTextColor;
+  }
+
+  /**
+   * Returns a UI delegate for the specified component.
+   * 
+   * @param c  the component (should be a subclass of {@link AbstractButton}).
+   * 
+   * @return A new instance of <code>MetalButtonUI</code>.
+   */
+  public static ComponentUI createUI(JComponent c) 
+  {
+    return new MetalButtonUI();
+  }
+
+  /**
+   * Installs the default settings for the specified button.
+   * 
+   * @param button  the button.
+   * 
+   * @see #uninstallDefaults(AbstractButton)
+   */
+  public void installDefaults(AbstractButton button)
+  {
+    super.installDefaults(button);
+    button.setRolloverEnabled(UIManager.getBoolean(
+                                            getPropertyPrefix() + "rollover"));
+  }
+    
+  /**
+   * Removes the defaults added by {@link #installDefaults(AbstractButton)}.
+   */
+  public void uninstallDefaults(AbstractButton button) 
+  {
+    super.uninstallDefaults(button);
+    button.setRolloverEnabled(false);
+  }
+
+  /**
+   * Returns a button listener for the specified button.
+   * 
+   * @param button  the button.
+   * 
+   * @return A button listener.
+   */
+  protected BasicButtonListener createButtonListener(AbstractButton button) 
+  {
+    return new MetalButtonListener(button);
+  }    
+
+  /**
+   * Paints the background of the button to indicate that it is in the
+   * "pressed" state.
+   * 
+   * @param g  the graphics context.
+   * @param b  the button.
+   */
+  protected void paintButtonPressed(Graphics g, AbstractButton b) 
+  { 
+    if (b.isContentAreaFilled())
+    {
+      Rectangle area = b.getVisibleRect();
+      g.setColor(selectColor);
+      g.fillRect(area.x, area.y, area.width, area.height);
+    }
+  }
+    
+  /** 
+   * Paints the focus rectangle around the button text and/or icon.
+   * 
+   * @param g  the graphics context.
+   * @param b  the button.
+   * @param viewRect  the button bounds.
+   * @param textRect  the text bounds.
+   * @param iconRect  the icon bounds.
+   */
+  protected void paintFocus(Graphics g, AbstractButton b, Rectangle viewRect,
+          Rectangle textRect, Rectangle iconRect) 
+  {
+    if (b.isEnabled() && b.hasFocus() && b.isFocusPainted())
+    {
+      Color savedColor = g.getColor();
+      g.setColor(getFocusColor());
+      Rectangle focusRect = iconRect.union(textRect);
+      g.drawRect(focusRect.x - 1, focusRect.y,
+                 focusRect.width + 1, focusRect.height);
+      g.setColor(savedColor);
+    }
+  }
+    
+  /**
+   * Paints the button text.
+   * 
+   * @param g  the graphics context.
+   * @param c  the button.
+   * @param textRect  the text bounds.
+   * @param text  the text to display.
+   */
+  protected void paintText(Graphics g, JComponent c, Rectangle textRect,
+          String text) 
+  {
+    AbstractButton b = (AbstractButton) c;
+    Font f = b.getFont();
+    g.setFont(f);
+    FontMetrics fm = g.getFontMetrics(f);
+
+    if (b.isEnabled())
+      {
+        g.setColor(b.getForeground());
+        g.drawString(text, textRect.x, textRect.y + fm.getAscent());
+      }
+    else
+      {
+        g.setColor(getDisabledTextColor());
+        g.drawString(text, textRect.x, textRect.y + fm.getAscent());
+      }  
+  }
+
+  /**
+   * If the property <code>Button.gradient</code> is set, then a gradient is
+   * painted as background, otherwise the normal superclass behaviour is
+   * called.
+   */
+  public void update(Graphics g, JComponent c)
+  {
+    AbstractButton b = (AbstractButton) c;
+    if ((b.getBackground() instanceof UIResource)
+        && b.isContentAreaFilled() && b.isEnabled())
+      {
+        ButtonModel m = b.getModel();
+        String uiKey = "Button.gradient";
+        if (! isToolbarButton(b))
+          {
+            if (! m.isArmed() && ! m.isPressed() && isDrawingGradient(uiKey))
+              {
+                MetalUtils.paintGradient(g, 0, 0, b.getWidth(), b.getHeight(),
+                                         SwingConstants.VERTICAL,
+                                         uiKey);
+                paint(g, c);
+                return;
+              }
+          }
+        else if (m.isRollover() && isDrawingGradient(uiKey))
+          {
+            MetalUtils.paintGradient(g, 0, 0, b.getWidth(), b.getHeight(),
+                                     SwingConstants.VERTICAL,
+                                     uiKey);
+            paint(g, c);
+            return;
+          }
+      }
+    // Fallback if we didn't have any of the two above cases.
+    super.update(g, c);
+  }
+
+  /**
+   * Returns <code>true</code> when the button is a toolbar button,
+   * <code>false</code> otherwise.
+   *
+   * @param b the button component to test
+   *
+   * @return <code>true</code> when the button is a toolbar button,
+   *         <code>false</code> otherwise
+   */
+  private boolean isToolbarButton(Component b)
+  {
+    Component parent = b.getParent();
+    return parent instanceof JToolBar;
+  }
+
+  /**
+   * Returns <code>true</code> if we should draw the button gradient,
+   * <code>false</code> otherwise.
+   *
+   * @param uiKey the UIManager key for the gradient
+   *
+   * @return <code>true</code> if we should draw the button gradient,
+   *         <code>false</code> otherwise
+   */
+  private boolean isDrawingGradient(String uiKey)
+  {
+    return (UIManager.get(uiKey) != null);
+  }
+}

Added: llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/metal/MetalCheckBoxIcon.java
URL: http://llvm.org/viewvc/llvm-project/llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/metal/MetalCheckBoxIcon.java?rev=43913&view=auto

==============================================================================
--- llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/metal/MetalCheckBoxIcon.java (added)
+++ llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/metal/MetalCheckBoxIcon.java Thu Nov  8 16:56:19 2007
@@ -0,0 +1,141 @@
+/* MetalCheckBoxIcon.java -- An icon for JCheckBoxes in the Metal L&F
+   Copyright (C) 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package javax.swing.plaf.metal;
+
+import java.awt.Component;
+import java.awt.Graphics;
+import java.io.Serializable;
+
+import javax.swing.Icon;
+import javax.swing.JCheckBox;
+import javax.swing.SwingConstants;
+import javax.swing.UIManager;
+import javax.swing.plaf.UIResource;
+
+/**
+ * An {@link Icon} used by the {@link MetalCheckBoxUI} class.
+ *
+ * @author Roman Kennke (roman at kennke.org)
+ */
+public class MetalCheckBoxIcon
+  implements Icon, UIResource, Serializable
+{
+
+  /** Used to paint the border of the icon. */
+  MetalBorders.ButtonBorder border;
+
+  /**
+   * Creates a new MetalCheckBoxIcon instance.
+   */
+  public MetalCheckBoxIcon()
+  {
+    border = new MetalBorders.ButtonBorder();
+  }
+
+  /**
+   * Draws the check in the CheckBox.
+   *
+   * @param c the component to draw on
+   * @param g the Graphics context to draw with
+   * @param x the X position
+   * @param y the Y position
+   */
+  protected void drawCheck(Component c, Graphics g, int x, int y)
+  {
+    if (c.isEnabled())
+      g.setColor(MetalLookAndFeel.getBlack());
+    else
+      g.setColor(MetalLookAndFeel.getControlDisabled());
+    g.drawLine(3 + x, 5 + y, 3 + x, 9 + y);
+    g.drawLine(4 + x, 5 + y, 4 + x, 9 + y);
+    g.drawLine(5 + x, 7 + y, 9 + x, 3 + y);
+    g.drawLine(5 + x, 8 + y, 9 + x, 4 + y);
+  }
+
+  /**
+   * Returns the size (both X and Y) of the checkbox icon.
+   *
+   * @return the size of the checkbox icon
+   */
+  protected int getControlSize()
+  {
+    return 13;
+  }
+
+  /**
+   * Returns the width of the icon in pixels.
+   *
+   * @return the width of the icon in pixels
+   */
+  public int getIconWidth()
+  {
+    return getControlSize();
+  }
+
+  /**
+   * Returns the height of the icon in pixels.
+   *
+   * @return the height of the icon in pixels
+   */
+  public int getIconHeight()
+  {
+    return getControlSize();
+  }
+
+  /**
+   * Paints the icon. This first paints the border of the CheckBox and
+   * if the CheckBox is selected it calls {@link #drawCheck} to draw
+   * the check.
+   *
+   * @param c the Component to draw on (gets casted to JCheckBox)
+   * @param g the Graphics context to draw with
+   * @param x the X position
+   * @param y the Y position
+   */
+  public void paintIcon(Component c, Graphics g, int x, int y)
+  {
+    if (UIManager.get("CheckBox.gradient") != null)
+      MetalUtils.paintGradient(g, x, y, getIconWidth(), getIconHeight(),
+                               SwingConstants.VERTICAL, "CheckBox.gradient");
+    border.paintBorder(c, g, x, y, getIconWidth(), getIconHeight());
+    JCheckBox cb = (JCheckBox) c;
+    if (cb.isSelected())
+      drawCheck(c, g, x, y);
+  }
+}

Added: llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/metal/MetalCheckBoxUI.java
URL: http://llvm.org/viewvc/llvm-project/llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/metal/MetalCheckBoxUI.java?rev=43913&view=auto

==============================================================================
--- llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/metal/MetalCheckBoxUI.java (added)
+++ llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/metal/MetalCheckBoxUI.java Thu Nov  8 16:56:19 2007
@@ -0,0 +1,89 @@
+/* MetalCheckBoxUI.java
+   Copyright (C) 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package javax.swing.plaf.metal;
+
+import javax.swing.JCheckBox;
+import javax.swing.JComponent;
+import javax.swing.UIDefaults;
+import javax.swing.plaf.ComponentUI;
+
+/**
+ * A UI delegate for the {@link JCheckBox} component.
+ */
+public class MetalCheckBoxUI
+  extends MetalRadioButtonUI
+{
+
+  // FIXME: maybe replace by a Map of instances when this becomes stateful
+  /** The shared UI instance for JCheckBoxes. */
+  private static MetalCheckBoxUI instance;
+
+  /**
+   * Constructs a new instance of MetalCheckBoxUI.
+   */
+  public MetalCheckBoxUI()
+  {
+    super();
+  }
+
+  /**
+   * Returns a shared instance of <code>MetalCheckBoxUI</code>.
+   *
+   * @param component the component for which we return an UI instance
+   *
+   * @return A shared instance of <code>MetalCheckBoxUI</code>.
+   */
+  public static ComponentUI createUI(JComponent component)
+  {
+    if (instance == null)
+      instance = new MetalCheckBoxUI();
+    return instance;
+  }
+  
+  /**
+   * Returns the prefix for properties defined in the {@link UIDefaults} table.
+   * 
+   * @return The property prefix (<code>"CheckBox."</code>).
+   */
+  public String getPropertyPrefix()
+  {
+    return "CheckBox.";
+  }
+}
+

Added: llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/metal/MetalComboBoxButton.java
URL: http://llvm.org/viewvc/llvm-project/llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/metal/MetalComboBoxButton.java?rev=43913&view=auto

==============================================================================
--- llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/metal/MetalComboBoxButton.java (added)
+++ llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/metal/MetalComboBoxButton.java Thu Nov  8 16:56:19 2007
@@ -0,0 +1,294 @@
+/* MetalComboBoxButton.java
+   Copyright (C) 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package javax.swing.plaf.metal;
+
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Graphics;
+import java.awt.Insets;
+
+import javax.swing.CellRendererPane;
+import javax.swing.Icon;
+import javax.swing.JButton;
+import javax.swing.JComboBox;
+import javax.swing.JList;
+import javax.swing.ListCellRenderer;
+import javax.swing.UIManager;
+
+/**
+ * A button used by the {@link MetalComboBoxUI} class.
+ */
+public class MetalComboBoxButton
+  extends JButton
+{
+
+  /** A reference to the JComboBox that the button belongs to. */
+  protected JComboBox comboBox;
+
+  /** A reference to the JList. */
+  protected JList listBox;
+  
+  /**
+   * Used for rendering the selected item.
+   */
+  protected CellRendererPane rendererPane;
+  
+  /** The button icon. */
+  protected Icon comboIcon;
+  
+  /** Display just the icon, or the icon plus the label. */
+  protected boolean iconOnly;
+  
+  /**
+   * Creates a new button.
+   * 
+   * @param cb  the combo that the button is used for (<code>null</code> not 
+   *            permitted).
+   * @param i  the icon displayed on the button.
+   * @param pane  the rendering pane.
+   * @param list  the list.
+   */
+  public MetalComboBoxButton(JComboBox cb, Icon i, CellRendererPane pane,
+      JList list)
+  {
+    this(cb, i, cb.isEditable(), pane, list);  
+  }
+  
+  /**
+   * Creates a new button.
+   * 
+   * @param cb  the combo that the button is used for (<code>null</code> not 
+   *            permitted).
+   * @param i  the icon displayed on the button.
+   * @param onlyIcon  a flag that specifies whether the button displays only an
+   *                  icon, or text as well.
+   * @param pane  the rendering pane.
+   * @param list  the list.
+   */
+  public MetalComboBoxButton(JComboBox cb, Icon i, boolean onlyIcon,
+      CellRendererPane pane, JList list)
+  {
+    super();
+    if (cb == null)
+      throw new NullPointerException("Null 'cb' argument");
+    comboBox = cb;
+    comboIcon = i;
+    iconOnly = onlyIcon;
+    listBox = list;
+    rendererPane = pane;
+    setRolloverEnabled(false);
+    setEnabled(comboBox.isEnabled());
+    setFocusable(comboBox.isEnabled());
+  }
+  
+  /**
+   * Returns the combo box that the button is used with.
+   * 
+   * @return The combo box.
+   */
+  public final JComboBox getComboBox()
+  {
+    return comboBox;
+  }
+  
+  /**
+   * Sets the combo box that the button is used with.
+   * 
+   * @param cb  the combo box.
+   */
+  public final void setComboBox(JComboBox cb)
+  {
+    comboBox = cb;
+  }
+  
+  /**
+   * Returns the icon displayed by the button.  By default, this will be an
+   * instance of {@link MetalComboBoxIcon}.
+   * 
+   * @return The icon displayed by the button.
+   */
+  public final Icon getComboIcon()
+  {
+    return comboIcon;
+  }
+  
+  /**
+   * Sets the icon displayed by the button.
+   * 
+   * @param i  the icon.
+   */
+  public final void setComboIcon(Icon i)
+  {
+    comboIcon = i;
+  }
+  
+  /**
+   * Returns a flag that controls whether the button displays an icon only,
+   * or text as well.
+   * 
+   * @return A boolean.
+   */
+  public final boolean isIconOnly()
+  {
+    return iconOnly;
+  }
+  
+  /**
+   * Sets the flag that controls whether the button displays an icon only,
+   * or text as well.
+   * 
+   * @param isIconOnly  the flag.
+   */
+  public final void setIconOnly(boolean isIconOnly)
+  {
+    iconOnly = isIconOnly;
+  }
+  
+  /**
+   * Returns <code>false</code>, to indicate that this component is not part
+   * of the focus traversal group.
+   * 
+   * @return <code>false</code>
+   */
+  public boolean isFocusTraversable()
+  {
+    return false;
+  }
+  
+  /**
+   * Enables or disables the button.
+   * 
+   * @param enabled  the new status.
+   */
+  public void setEnabled(boolean enabled)
+  {
+    super.setEnabled(enabled);
+    if (enabled)
+      {
+        setBackground(comboBox.getBackground());
+        setForeground(comboBox.getForeground());
+      }
+    else
+      {
+        setBackground(UIManager.getColor("ComboBox.disabledBackground"));
+        setForeground(UIManager.getColor("ComboBox.disabledForeground"));
+      }
+  }
+  
+  /**
+   * Paints the component.
+   * 
+   * @param g  the graphics device.
+   */
+  public void paintComponent(Graphics g)
+  {
+    super.paintComponent(g);
+    Insets insets = this.getInsets();
+    int w = getWidth() - (insets.left + insets.right);
+    int h = getHeight() - (insets.top + insets.bottom);
+    if (h > 0 && w > 0)
+      {
+        int x1 = insets.left;
+        int y1 = insets.top;
+        int x2 = x1 + (w - 1);
+        int y2 = y1 + (h - 1);
+        int iconWidth = 0;
+        int iconX = x2;
+        if (comboIcon != null)
+          {
+            iconWidth = comboIcon.getIconWidth();
+            int iconHeight = comboIcon.getIconHeight();
+            int iconY;
+            if (iconOnly)
+              {
+                iconX = getWidth() / 2 - iconWidth / 2;
+                iconY = getHeight() / 2 - iconHeight / 2;
+              }
+            else
+              {
+                iconX = x1 + (w - 1) - iconWidth;
+                iconY = y1 + (y2 - y1) / 2 - iconHeight / 2;
+              }
+            comboIcon.paintIcon(this, g, iconX, iconY);
+            if (this.hasFocus())
+              {
+                g.setColor(MetalLookAndFeel.getFocusColor());
+                g.drawRect(x1 - 1, y1 - 1, w + 3, h + 1);
+              }
+          }
+        if (! iconOnly && comboBox != null)
+          {
+            ListCellRenderer renderer = comboBox.getRenderer();
+            boolean pressed = this.getModel().isPressed();
+            Component comp = renderer.getListCellRendererComponent(listBox,
+                comboBox.getSelectedItem(), -1, false, false);
+            comp.setFont(rendererPane.getFont());
+            
+            if ((model.isArmed() && model.isPressed())
+                || (comboBox.isFocusOwner() && !comboBox.isPopupVisible()))
+              {
+                if (isOpaque())
+                  {
+                    comp.setBackground(UIManager.getColor("Button.select"));
+                    comp.setForeground(comboBox.getForeground());
+                  }
+              }
+            else if (! comboBox.isEnabled())
+              {
+                if (this.isOpaque())
+                  {
+                    Color dbg =
+                      UIManager.getColor("ComboBox.disabledBackground");
+                    comp.setBackground(dbg);
+                    Color dfg =
+                      UIManager.getColor("ComboBox.disabledForeground");
+                    comp.setForeground(dfg);
+                  }
+              }
+            else
+              {
+                comp.setForeground(comboBox.getForeground());
+                comp.setBackground(comboBox.getBackground());
+              }
+            int wr = w - (insets.right + iconWidth);
+            rendererPane.paintComponent(g, comp, this, x1, y1, wr, h);
+          }
+      }
+  }
+}

Added: llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/metal/MetalComboBoxEditor.java
URL: http://llvm.org/viewvc/llvm-project/llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/metal/MetalComboBoxEditor.java?rev=43913&view=auto

==============================================================================
--- llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/metal/MetalComboBoxEditor.java (added)
+++ llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/metal/MetalComboBoxEditor.java Thu Nov  8 16:56:19 2007
@@ -0,0 +1,190 @@
+/* MetalComboBoxEditor.java
+   Copyright (C) 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package javax.swing.plaf.metal;
+
+import java.awt.Component;
+import java.awt.Dimension;
+import java.awt.Graphics;
+import java.awt.Insets;
+
+import javax.swing.JTextField;
+import javax.swing.border.AbstractBorder;
+import javax.swing.plaf.basic.BasicComboBoxEditor;
+import javax.swing.plaf.metal.MetalLookAndFeel;
+
+/**
+ * An editor used by the {@link MetalComboBoxUI} class.
+ */
+public class MetalComboBoxEditor extends BasicComboBoxEditor
+{
+  /**
+   * A border used for the {@link JTextField} component.
+   */
+  static class MetalComboBoxEditorBorder extends AbstractBorder
+  {
+    /**
+     * Creates a new border instance.
+     */
+    public MetalComboBoxEditorBorder()
+    {
+      // Nothing to do here.
+    }
+    
+    /**
+     * Paints the border for the specified component.
+     * 
+     * @param c  the component (ignored).
+     * @param g  the graphics device.
+     * @param x  the x-coordinate.
+     * @param y  the y-coordinate.
+     * @param w  the width.
+     * @param h  the height.
+     */
+    public void paintBorder(Component c, Graphics g, int x, int y, int w, 
+        int h)
+    {
+      g.translate(x, y);
+      if (MetalLookAndFeel.getCurrentTheme() instanceof OceanTheme)
+        {
+          g.setColor(MetalLookAndFeel.getControlDarkShadow());
+          g.drawLine(0, 0, w - 1, 0);
+          g.drawLine(0, 0, 0, h - 1);
+          g.drawLine(0, h - 1, w - 1, h - 1);
+          g.setColor(MetalLookAndFeel.getControlShadow());
+          g.drawLine(1, 1, w - 2, 1);
+          g.drawLine(1, 1, 1, h - 2);
+          g.drawLine(1, h - 2, w - 1, h - 2);
+          g.drawLine(w - 1, 1, w - 1, h - 2);
+        }
+      else
+        {
+          g.setColor(MetalLookAndFeel.getControlDarkShadow());
+          g.drawLine(0, 0, w - 1, 0);
+          g.drawLine(0, 0, 0, h - 2);
+          g.drawLine(0, h - 2, w - 1, h - 2);
+          g.setColor(MetalLookAndFeel.getControlHighlight());
+          g.drawLine(1, 1, w - 1, 1);
+          g.drawLine(1, 1, 1, h - 1);
+          g.drawLine(1, h - 1, w - 1, h - 1);
+          g.setColor(MetalLookAndFeel.getControl());
+          g.drawLine(1, h - 2, 1, h - 2);
+        }
+      g.translate(-x, -y);
+    }
+
+    /**
+     * Measures the width of this border.
+     *
+     * @param c the component whose border is to be measured.
+     *
+     * @return an Insets object whose <code>left</code>, <code>right</code>,
+     *         <code>top</code> and <code>bottom</code> fields indicate the
+     *         width of the border at the respective edge, which is zero
+     *         for the default implementation provided by AbstractButton.
+     *
+     * @see #getBorderInsets(java.awt.Component, java.awt.Insets)
+     */
+    public Insets getBorderInsets(Component c)
+    {
+      return editorBorderInsets;
+    }    
+  }
+    
+  /**
+   * A subclass of {@link MetalComboBoxEditor} that implements the 
+   * {@link javax.swing.plaf.UIResource} interface.
+   */
+  public static class UIResource extends MetalComboBoxEditor
+    implements javax.swing.plaf.UIResource
+  {
+    /**
+     * Creates a new instance.
+     */
+    public UIResource()
+    {
+      // Nothing to do here.
+    }
+  }
+
+  /**
+   * A special textfield implementation for the MetalComboBoxEditor.
+   */
+  private class EditorTextField extends JTextField
+  {
+    EditorTextField(String s, int columns)
+    {
+      super(s, columns);
+    }
+
+    /**
+     * Tests seem to show that the textfield in MetalComboBoxEditors have
+     * a height + 4.
+     */
+    public Dimension getPreferredSize()
+    {
+      Dimension size = super.getPreferredSize();
+      size.height += 4;
+      return size;
+    }
+
+    /**
+     * Tests seem to show that the textfield in MetalComboBoxEditors have
+     * a height + 4.
+     */
+    public Dimension getMinimumSize()
+    {
+      Dimension size = super.getMinimumSize();
+      size.height += 4;
+      return size;
+    }
+  }
+
+  /** The editor's border insets. */
+  protected static Insets editorBorderInsets = new Insets(2, 2, 2, 0);
+  
+  /**
+   * Creates a new editor.
+   */
+  public MetalComboBoxEditor()
+  {
+    editor = new EditorTextField("", 9);
+    editor.setBorder(new MetalComboBoxEditorBorder());
+  }
+  
+}

Added: llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/metal/MetalComboBoxIcon.java
URL: http://llvm.org/viewvc/llvm-project/llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/metal/MetalComboBoxIcon.java?rev=43913&view=auto

==============================================================================
--- llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/metal/MetalComboBoxIcon.java (added)
+++ llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/metal/MetalComboBoxIcon.java Thu Nov  8 16:56:19 2007
@@ -0,0 +1,102 @@
+/* MetalComboBoxIcon.java
+   Copyright (C) 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package javax.swing.plaf.metal;
+
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Graphics;
+import java.io.Serializable;
+
+import javax.swing.Icon;
+
+/**
+ * An icon used by the {@link MetalComboBoxUI} class.
+ */
+public class MetalComboBoxIcon implements Icon, Serializable 
+{
+  
+  /**
+   * Creates a new icon.
+   */
+  public MetalComboBoxIcon() 
+  {
+    // nothing required.
+  }
+  
+  /**
+   * Returns the icon width, which for this icon is 10 pixels.
+   * 
+   * @return <code>10</code>.
+   */
+  public int getIconWidth()
+  {
+    return 10;
+  }
+
+  /**
+   * Returns the icon height, which for this icon is 5 pixels.
+   * 
+   * @return <code>5</code>.
+   */
+  public int getIconHeight()
+  {
+    return 5;
+  }
+
+  /**
+   * Paints the icon at the location (x, y).
+   * 
+   * @param c  the combo box (ignored here).
+   * @param g  the graphics device.
+   * @param x  the x coordinate.
+   * @param y  the y coordinate.
+   */
+  public void paintIcon(Component c, Graphics g, int x, int y)
+  {
+    Color savedColor = g.getColor();
+    if (c.isEnabled())
+      g.setColor(MetalLookAndFeel.getBlack());
+    else
+      g.setColor(MetalLookAndFeel.getControlDisabled());
+    for (int i = 0; i < 5; i++)
+      g.drawLine(x + i, y + i, x + 9 - i, y + i);
+    g.setColor(savedColor);
+  }
+
+}

Added: llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/metal/MetalComboBoxUI.java
URL: http://llvm.org/viewvc/llvm-project/llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/metal/MetalComboBoxUI.java?rev=43913&view=auto

==============================================================================
--- llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/metal/MetalComboBoxUI.java (added)
+++ llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/metal/MetalComboBoxUI.java Thu Nov  8 16:56:19 2007
@@ -0,0 +1,374 @@
+/* MetalComboBoxUI.java
+   Copyright (C) 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package javax.swing.plaf.metal;
+
+import java.awt.Color;
+import java.awt.Container;
+import java.awt.Dimension;
+import java.awt.Graphics;
+import java.awt.Insets;
+import java.awt.LayoutManager;
+import java.awt.event.MouseEvent;
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+
+import javax.swing.CellRendererPane;
+import javax.swing.ComboBoxEditor;
+import javax.swing.Icon;
+import javax.swing.JButton;
+import javax.swing.JComboBox;
+import javax.swing.JComponent;
+import javax.swing.plaf.ComponentUI;
+import javax.swing.plaf.basic.BasicComboBoxUI;
+import javax.swing.plaf.basic.BasicComboPopup;
+import javax.swing.plaf.basic.ComboPopup;
+
+
+/**
+ * A UI delegate for the {@link JComboBox} component.
+ */
+public class MetalComboBoxUI extends BasicComboBoxUI
+{
+  /**
+   * A layout manager that arranges the editor component (if active) and the
+   * button that make up the combo box.
+   */
+  public class MetalComboBoxLayoutManager
+    extends BasicComboBoxUI.ComboBoxLayoutManager
+  {
+    /**
+     * Creates a new instance of the layout manager.
+     */
+    public MetalComboBoxLayoutManager()
+    {
+      // Nothing to do here.
+    }
+    
+    /**
+     * Arranges the editor (if visible) and button that comprise the combo
+     * box.
+     * 
+     * @param parent  the parent.
+     */
+    public void layoutContainer(Container parent)
+    {
+      layoutComboBox(parent, this);
+    }
+    
+    /**
+     * Calls the <code>layoutContainer(Container)</code> method in the super 
+     * class.
+     * 
+     * @param parent  the container.
+     */
+    public void superLayout(Container parent)
+    {
+      super.layoutContainer(parent);
+    }
+  }
+  
+  /**
+   * A listener used to handle property changes in the {@link JComboBox} 
+   * component, to ensure that the UI delegate accurately reflects the current
+   * state in the rendering onscreen.
+   */
+  public class MetalPropertyChangeListener
+    extends BasicComboBoxUI.PropertyChangeHandler
+  {
+    /**
+     * Creates a new listener.
+     */
+    public MetalPropertyChangeListener()
+    {
+      // Nothing to do here.
+    }
+    
+    /**
+     * Handles a property change event, updating the UI components as
+     * appropriate.
+     * 
+     * @param e  the event.
+     */
+    public void propertyChange(PropertyChangeEvent e)
+    {
+      super.propertyChange(e);
+      String name = e.getPropertyName();
+      if (name.equals("editable"))
+        editablePropertyChanged(e);
+      else if (name.equals("enabled"))
+        {
+          if (arrowButton instanceof MetalComboBoxButton)
+            {
+              arrowButton.setFocusable(!comboBox.isEditable()
+                                       && comboBox.isEnabled());
+              comboBox.repaint();
+            }
+        }
+      else if (name.equals("background"))
+        {
+          Color c = (Color) e.getNewValue();
+          arrowButton.setBackground(c);
+          listBox.setBackground(c);
+        }
+      else if (name.equals("foreground"))
+        {
+          Color c = (Color) e.getNewValue();
+          arrowButton.setForeground(c);
+          listBox.setForeground(c);
+        }
+    }
+  }
+
+  /**
+   * A popup menu for the combo-box.
+   * 
+   * @see #createPopup()
+   *
+   * @deprecated 1.4
+   */
+  public class MetalComboPopup extends BasicComboPopup
+  {
+    /**
+     * Creates a new popup.
+     * 
+     * @param cBox  the combo box.
+     */
+    public MetalComboPopup(JComboBox cBox)
+    {
+      super(cBox); 
+    }
+    
+    public void delegateFocus(MouseEvent e)
+    {
+      super.delegateFocus(e);
+    }
+  }
+  
+  /**
+   * Constructs a new instance of MetalComboBoxUI.
+   */
+  public MetalComboBoxUI()
+  {
+    super();
+  }
+
+  /**
+   * Returns an instance of MetalComboBoxUI.
+   *
+   * @param component the component for which we return an UI instance
+   *
+   * @return an instance of MetalComboBoxUI
+   */
+  public static ComponentUI createUI(JComponent component)
+  {
+    return new MetalComboBoxUI();
+  }
+  
+  /**
+   * Creates an editor for the combo box.
+   * 
+   * @return An editor.
+   */
+  protected ComboBoxEditor createEditor()
+  {
+    return new MetalComboBoxEditor.UIResource();   
+  }
+  
+  /**
+   * Creates a popup for the combo box.
+   * 
+   * @return A popup.
+   */
+  protected ComboPopup createPopup()
+  {
+    return new MetalComboPopup(comboBox);
+  }
+  
+  /**
+   * Creates a new button for use in rendering the JComboBox.
+   * 
+   * @return A button.
+   */
+  protected JButton createArrowButton()
+  {
+    JButton button = new MetalComboBoxButton(comboBox, new MetalComboBoxIcon(), 
+            new CellRendererPane(), listBox);  
+    button.setMargin(new Insets(0, 1, 1, 3));
+    return button;
+  }
+  
+  /**
+   * Creates a new property change listener.
+   * 
+   * @return A new property change listener.
+   */
+  public PropertyChangeListener createPropertyChangeListener()
+  {
+    return new MetalPropertyChangeListener();
+  }
+  
+  public void paint(Graphics g, JComponent c)
+  {
+    // do nothing, the button and text field are painted elsewhere
+  }
+  
+  /**
+   * Updates the button and text field to reflect a change in the 'editable'
+   * property.
+   * 
+   * @param e  the event.
+   * 
+   * @deprecated 1.4
+   */
+  protected void editablePropertyChanged(PropertyChangeEvent e)
+  {
+    if (arrowButton instanceof MetalComboBoxButton)
+      {
+        MetalComboBoxButton b = (MetalComboBoxButton) arrowButton;
+        b.setIconOnly(comboBox.isEditable());
+        b.setFocusable(!comboBox.isEditable() && comboBox.isEnabled());
+        comboBox.repaint();
+      }
+  }
+  
+  /**
+   * Creates a new layout manager for the UI delegate.
+   * 
+   * @return A new layout manager.
+   */
+  protected LayoutManager createLayoutManager()
+  {
+    return new MetalComboBoxLayoutManager();
+  }
+  
+  /**
+   * Not used in Classpath.
+   * 
+   * @deprecated 1.4
+   */
+  protected void removeListeners()
+  {
+    // no longer used in JDK 1.4 
+  }
+  
+  /**
+   * Returns the minimum size for the combo.
+   * 
+   * @param c  the component
+   * 
+   * @return The minimum size for the combo box.
+   */
+  public Dimension getMinimumSize(JComponent c)
+  {
+    if (!isMinimumSizeDirty)
+      return new Dimension(cachedMinimumSize);
+
+    Dimension d;
+    if (!comboBox.isEditable() && arrowButton != null
+        && arrowButton instanceof MetalComboBoxButton)
+      {
+        MetalComboBoxButton b = (MetalComboBoxButton) arrowButton;
+        d = getDisplaySize();
+        Insets insets = b.getInsets();
+        Insets arrowInsets = b.getInsets();
+        Insets comboInsets = comboBox.getInsets();
+        Icon icon = b.getComboIcon();
+        d.width += comboInsets.left + comboInsets.right;
+        d.width += arrowInsets.left + arrowInsets.right;
+        d.width += arrowInsets.right + icon.getIconWidth();
+        d.height += comboInsets.top + comboInsets.bottom;
+        d.height += arrowInsets.top + arrowInsets.bottom;
+      }
+    else if (comboBox.isEditable() && arrowButton != null && editor != null)
+      {
+        d = super.getMinimumSize(c);
+        Insets arrowMargin = arrowButton.getMargin();
+        d.height += arrowMargin.top + arrowMargin.bottom;
+        d.width += arrowMargin.left + arrowMargin.right;
+      }
+    else
+      {
+        d = super.getMinimumSize(c);
+      }
+    cachedMinimumSize.setSize(d.width, d.height);
+    isMinimumSizeDirty = false;
+    return new Dimension(cachedMinimumSize);
+  }
+  
+  /**
+   * Configures the editor for this combo box.
+   */
+  public void configureEditor()
+  {
+    super.configureEditor();
+    if (popupKeyListener != null)
+      editor.removeKeyListener(popupKeyListener);
+    if (focusListener != null)
+      editor.addFocusListener(focusListener);
+  }
+
+  /**
+   * Unconfigures the editor for this combo box.
+   */
+  public void unconfigureEditor()
+  {
+    super.unconfigureEditor();
+    if (focusListener != null)
+      editor.removeFocusListener(focusListener);
+  }
+  
+  /** 
+   * Lays out the ComboBox
+   */
+  public void layoutComboBox(Container parent,
+                             MetalComboBoxUI.MetalComboBoxLayoutManager manager)
+  {
+    if (comboBox.isEditable())
+      manager.superLayout(parent);
+    else if (arrowButton != null)
+      {
+        Insets comboInsets = comboBox.getInsets();
+        int width = comboBox.getWidth();
+        int height = comboBox.getHeight();
+        arrowButton.setBounds(comboInsets.left, comboInsets.top,
+                              width - (comboInsets.left + comboInsets.right),
+                              height - (comboInsets.top + comboInsets.bottom));
+      }
+  }
+}

Added: llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/metal/MetalDesktopIconUI.java
URL: http://llvm.org/viewvc/llvm-project/llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/metal/MetalDesktopIconUI.java?rev=43913&view=auto

==============================================================================
--- llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/metal/MetalDesktopIconUI.java (added)
+++ llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/metal/MetalDesktopIconUI.java Thu Nov  8 16:56:19 2007
@@ -0,0 +1,72 @@
+/* MetalDesktopIconUI.java
+   Copyright (C) 2005, 2006, Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package javax.swing.plaf.metal;
+
+import javax.swing.JComponent;
+import javax.swing.JInternalFrame;
+import javax.swing.plaf.ComponentUI;
+import javax.swing.plaf.basic.BasicDesktopIconUI;
+
+/**
+ * A UI delegate for the {@link JInternalFrame.JDesktopIcon} component.
+ */
+public class MetalDesktopIconUI
+  extends BasicDesktopIconUI
+{
+
+  /**
+   * Constructs a new instance of <code>MetalDesktopIconUI</code>.
+   */
+  public MetalDesktopIconUI()
+  {
+    super();
+  }
+
+  /**
+   * Returns a new <code>MetalDesktopIconUI</code> instance.
+   *
+   * @param component  the component (ignored).
+   *
+   * @return A new <code>MetalDesktopIconUI</code> instance.
+   */
+  public static ComponentUI createUI(JComponent component)
+  {
+    return new MetalDesktopIconUI();
+  }
+}

Added: llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/metal/MetalFileChooserUI.java
URL: http://llvm.org/viewvc/llvm-project/llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/metal/MetalFileChooserUI.java?rev=43913&view=auto

==============================================================================
--- llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/metal/MetalFileChooserUI.java (added)
+++ llvm-gcc-4.2/trunk/libjava/classpath/javax/swing/plaf/metal/MetalFileChooserUI.java Thu Nov  8 16:56:19 2007
@@ -0,0 +1,2120 @@
+/* MetalFileChooserUI.java --
+   Copyright (C) 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package javax.swing.plaf.metal;
+
+import java.awt.BorderLayout;
+import java.awt.Component;
+import java.awt.Container;
+import java.awt.Dimension;
+import java.awt.Graphics;
+import java.awt.GridLayout;
+import java.awt.Insets;
+import java.awt.LayoutManager;
+import java.awt.Rectangle;
+import java.awt.Window;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseListener;
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+import java.io.File;
+import java.sql.Date;
+import java.text.DateFormat;
+import java.text.NumberFormat;
+import java.util.List;
+
+import javax.swing.AbstractAction;
+import javax.swing.AbstractListModel;
+import javax.swing.ActionMap;
+import javax.swing.BorderFactory;
+import javax.swing.ButtonGroup;
+import javax.swing.ComboBoxModel;
+import javax.swing.DefaultListCellRenderer;
+import javax.swing.Icon;
+import javax.swing.JButton;
+import javax.swing.JComboBox;
+import javax.swing.JComponent;
+import javax.swing.JDialog;
+import javax.swing.JFileChooser;
+import javax.swing.JLabel;
+import javax.swing.JList;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JTable;
+import javax.swing.JTextField;
+import javax.swing.JToggleButton;
+import javax.swing.ListModel;
+import javax.swing.ListSelectionModel;
+import javax.swing.SwingUtilities;
+import javax.swing.UIManager;
+import javax.swing.event.ListSelectionEvent;
+import javax.swing.event.ListSelectionListener;
+import javax.swing.filechooser.FileFilter;
+import javax.swing.filechooser.FileSystemView;
+import javax.swing.filechooser.FileView;
+import javax.swing.plaf.ComponentUI;
+import javax.swing.plaf.basic.BasicFileChooserUI;
+import javax.swing.table.DefaultTableCellRenderer;
+import javax.swing.table.DefaultTableModel;
+
+
+/**
+ * A UI delegate for the {@link JFileChooser} component.  This class is only
+ * partially implemented and is not usable yet.
+ */
+public class MetalFileChooserUI 
+  extends BasicFileChooserUI
+{
+  
+  /**
+   * A renderer for the files and directories in the file chooser table.
+   */
+  class TableFileRenderer
+    extends DefaultTableCellRenderer
+  {
+    
+    /**
+     * Creates a new renderer.
+     */
+    public TableFileRenderer()
+    {
+      super();
+    }
+    
+    /**
+     * Returns a component that can render the specified value.
+     * 
+     * @param table  the table
+     * @param value  the string value of the cell
+     * @param isSelected  is the item selected?
+     * @param hasFocus  does the item have the focus?
+     * @param row  the row
+     * @param column  the column
+     * 
+     * @return The renderer.
+     */
+    public Component getTableCellRendererComponent(JTable table, Object value,
+        boolean isSelected, boolean hasFocus, int row, int column)
+    {
+      if (column == 0)
+        {
+          FileView v = getFileView(getFileChooser());
+          ListModel lm = fileList.getModel();
+          if (row < lm.getSize())
+            setIcon(v.getIcon((File) lm.getElementAt(row)));
+        }
+      else
+        setIcon(null);
+      
+      setText(value.toString());
+      setOpaque(true);
+      setEnabled(table.isEnabled());
+      setFont(fileList.getFont());
+      
+      if (startEditing && column == 0 || !isSelected)
+        {
+          setBackground(table.getBackground());
+          setForeground(table.getForeground());
+        }
+      else
+        {
+          setBackground(table.getSelectionBackground());
+          setForeground(table.getSelectionForeground());
+        }
+
+      if (hasFocus)
+        setBorder(UIManager.getBorder("Table.focusCellHighlightBorder"));
+      else
+        setBorder(noFocusBorder);
+      
+      return this;
+    }
+  }
+  
+  /**
+   * ActionListener for the list view.
+   */
+  class ListViewActionListener implements ActionListener
+  {
+    
+    /**
+     * This method is invoked when an action occurs.
+     * 
+     * @param e -
+     *          the <code>ActionEvent</code> that occurred
+     */
+    public void actionPerformed(ActionEvent e)
+    {
+      if (!listView)
+        {
+          int[] index = fileTable.getSelectedRows();
+          listView = true;
+          JFileChooser fc = getFileChooser();
+          fc.remove(fileTablePanel);
+          createList(fc);
+
+          fileList.getSelectionModel().clearSelection();
+          if (index.length > 0)
+              for (int i = 0; i < index.length; i++)
+                fileList.getSelectionModel().addSelectionInterval(index[i], index[i]);
+          
+          fc.add(fileListPanel, BorderLayout.CENTER);
+          fc.revalidate();
+          fc.repaint();
+        }
+    }
+  }
+  
+  /**
+   * ActionListener for the details view.
+   */
+  class DetailViewActionListener implements ActionListener
+  {
+    
+    /**
+     * This method is invoked when an action occurs.
+     * 
+     * @param e -
+     *          the <code>ActionEvent</code> that occurred
+     */
+    public void actionPerformed(ActionEvent e)
+    {
+      if (listView)
+        {
+          int[] index = fileList.getSelectedIndices();
+          JFileChooser fc = getFileChooser();
+          listView = false;
+          fc.remove(fileListPanel);
+          
+          if (fileTable == null)
+            createDetailsView(fc);
+          else
+            updateTable();
+
+          fileTable.getSelectionModel().clearSelection();
+          if (index.length > 0)
+            {
+              for (int i = 0; i < index.length; i++)
+                fileTable.getSelectionModel().addSelectionInterval(index[i], index[i]);
+            }
+          
+          fc.add(fileTablePanel, BorderLayout.CENTER);
+          fc.revalidate();
+          fc.repaint();
+        }
+    }
+  }
+  
+  /**
+   * A property change listener.
+   */
+  class MetalFileChooserPropertyChangeListener 
+    implements PropertyChangeListener
+  {
+    /**
+     * Default constructor.
+     */
+    public MetalFileChooserPropertyChangeListener()
+    {
+    }
+    
+    /**
+     * Handles a property change event.
+     * 
+     * @param e  the event.
+     */
+    public void propertyChange(PropertyChangeEvent e)
+    {
+      JFileChooser filechooser = getFileChooser();
+      
+      String n = e.getPropertyName();
+      if (n.equals(JFileChooser.MULTI_SELECTION_ENABLED_CHANGED_PROPERTY))
+        {
+          int mode = -1; 
+          if (filechooser.isMultiSelectionEnabled())
+            mode = ListSelectionModel.MULTIPLE_INTERVAL_SELECTION;
+          else
+            mode = ListSelectionModel.SINGLE_SELECTION;
+          
+          if (listView)
+            fileList.setSelectionMode(mode);
+          else
+            fileTable.setSelectionMode(mode);
+        }
+      else if (n.equals(JFileChooser.SELECTED_FILE_CHANGED_PROPERTY))
+        {
+          File file = filechooser.getSelectedFile();
+          
+          if (file != null
+              && filechooser.getDialogType() == JFileChooser.SAVE_DIALOG)
+            {
+              if (file.isDirectory() && filechooser.isTraversable(file))
+                {
+                  directoryLabel = look;
+                  dirLabel.setText(directoryLabel);
+                  filechooser.setApproveButtonText(openButtonText);
+                  filechooser.setApproveButtonToolTipText(openButtonToolTipText);
+                }
+              else if (file.isFile())
+                {
+                  directoryLabel = save;
+                  dirLabel.setText(directoryLabel);
+                  filechooser.setApproveButtonText(saveButtonText);
+                  filechooser.setApproveButtonToolTipText(saveButtonToolTipText);
+                }
+            }
+            
+          if (file == null)
+            setFileName(null);
+          else if (file.isFile() || filechooser.getFileSelectionMode() 
+		   != JFileChooser.FILES_ONLY)
+	    setFileName(file.getName());
+          int index = -1;
+          index = getModel().indexOf(file);
+          if (index >= 0)
+            {
+              if (listView)
+                {
+                  fileList.setSelectedIndex(index);
+                  fileList.ensureIndexIsVisible(index);
+                  fileList.revalidate();
+                  fileList.repaint();
+                }
+              else
+                {
+                  fileTable.getSelectionModel().addSelectionInterval(index, index);
+                  fileTable.scrollRectToVisible(fileTable.getCellRect(index, 0, true));
+                  fileTable.revalidate();
+                  fileTable.repaint();
+                }
+            }
+        }
+      
+      else if (n.equals(JFileChooser.DIRECTORY_CHANGED_PROPERTY))
+        {
+          if (listView)
+            {
+              fileList.clearSelection();
+              fileList.revalidate();
+              fileList.repaint();
+            }
+          else
+            {
+              fileTable.clearSelection();
+              fileTable.revalidate();
+              fileTable.repaint();
+            }
+
+          setDirectorySelected(false);
+          File currentDirectory = filechooser.getCurrentDirectory();
+          setDirectory(currentDirectory);
+          boolean hasParent = currentDirectory.getParentFile() != null;
+          getChangeToParentDirectoryAction().setEnabled(hasParent);
+        }
+      
+      else if (n.equals(JFileChooser.CHOOSABLE_FILE_FILTER_CHANGED_PROPERTY))
+        {
+          filterModel.propertyChange(e);
+        }
+      else if (n.equals(JFileChooser.FILE_FILTER_CHANGED_PROPERTY))
+        {
+          filterModel.propertyChange(e);
+        }
+      else if (n.equals(JFileChooser.DIALOG_TYPE_CHANGED_PROPERTY)
+                 || n.equals(JFileChooser.DIALOG_TITLE_CHANGED_PROPERTY))
+        {
+          Window owner = SwingUtilities.windowForComponent(filechooser);
+          if (owner instanceof JDialog)
+            ((JDialog) owner).setTitle(getDialogTitle(filechooser));
+          approveButton.setText(getApproveButtonText(filechooser));
+          approveButton.setToolTipText(
+                  getApproveButtonToolTipText(filechooser));
+          approveButton.setMnemonic(getApproveButtonMnemonic(filechooser));
+        }
+      
+      else if (n.equals(JFileChooser.APPROVE_BUTTON_TEXT_CHANGED_PROPERTY))
+        approveButton.setText(getApproveButtonText(filechooser));
+      
+      else if (n.equals(
+              JFileChooser.APPROVE_BUTTON_TOOL_TIP_TEXT_CHANGED_PROPERTY))
+        approveButton.setToolTipText(getApproveButtonToolTipText(filechooser));
+      
+      else if (n.equals(JFileChooser.APPROVE_BUTTON_MNEMONIC_CHANGED_PROPERTY))
+        approveButton.setMnemonic(getApproveButtonMnemonic(filechooser));
+
+      else if (n.equals(
+              JFileChooser.CONTROL_BUTTONS_ARE_SHOWN_CHANGED_PROPERTY))
+        {
+          if (filechooser.getControlButtonsAreShown())
+            {
+              topPanel.add(controls, BorderLayout.EAST);
+            }
+          else
+            topPanel.remove(controls);
+          topPanel.revalidate();
+          topPanel.repaint();
+          topPanel.doLayout();
+        }
+      
+      else if (n.equals(
+              JFileChooser.ACCEPT_ALL_FILE_FILTER_USED_CHANGED_PROPERTY))
+        {
+          if (filechooser.isAcceptAllFileFilterUsed())
+            filechooser.addChoosableFileFilter(
+                    getAcceptAllFileFilter(filechooser));
+          else
+            filechooser.removeChoosableFileFilter(
+                    getAcceptAllFileFilter(filechooser));
+        }
+      
+      else if (n.equals(JFileChooser.ACCESSORY_CHANGED_PROPERTY))
+        {
+          JComponent old = (JComponent) e.getOldValue();
+          if (old != null)
+            getAccessoryPanel().remove(old);
+          JComponent newval = (JComponent) e.getNewValue();
+          if (newval != null)
+            getAccessoryPanel().add(newval);
+        }
+      
+      if (n.equals(JFileChooser.DIRECTORY_CHANGED_PROPERTY)
+          || n.equals(JFileChooser.FILE_FILTER_CHANGED_PROPERTY)
+          || n.equals(JFileChooser.FILE_HIDING_CHANGED_PROPERTY))
+        {
+          // Remove editing component
+          if (fileTable != null)
+            fileTable.removeAll();
+          if (fileList != null)
+            fileList.removeAll();
+          startEditing = false;
+          
+          // Set text on button back to original.
+          if (filechooser.getDialogType() == JFileChooser.SAVE_DIALOG)
+            {
+              directoryLabel = save;
+              dirLabel.setText(directoryLabel);
+              filechooser.setApproveButtonText(saveButtonText);
+              filechooser.setApproveButtonToolTipText(saveButtonToolTipText);
+            }
+          
+          rescanCurrentDirectory(filechooser);
+        }
+      
+      filechooser.revalidate();
+      filechooser.repaint();
+    }
+  };
+  
+  /** 
+   * A combo box model containing the selected directory and all its parent
+   * directories.
+   */
+  protected class DirectoryComboBoxModel
+    extends AbstractListModel
+    implements ComboBoxModel
+  {
+    /** Storage for the items in the model. */
+    private List items;
+    
+    /** The index of the selected item. */
+    private int selectedIndex;
+    
+    /**
+     * Creates a new model.
+     */
+    public DirectoryComboBoxModel() 
+    {
+      items = new java.util.ArrayList();
+      selectedIndex = -1;
+    }
+    
+    /**
+     * Returns the number of items in the model.
+     * 
+     * @return The number of items in the model.
+     */
+    public int getSize()
+    {
+      return items.size();
+    }
+    
+    /**
+     * Returns the item at the specified index.
+     * 
+     * @param index  the item index.
+     * 
+     * @return The item.
+     */
+    public Object getElementAt(int index)
+    {
+      return items.get(index);
+    }
+    
+    /**
+     * Returns the depth of the item at the given <code>index</code>.
+     * 
+     * @param index  the item index.
+     * 
+     * @return The depth.
+     */
+    public int getDepth(int index)
+    {
+      return Math.max(index, 0);
+    }
+
+    /**
+     * Returns the selected item, or <code>null</code> if no item is selected.
+     * 
+     * @return The selected item, or <code>null</code>.
+     */
+    public Object getSelectedItem()
+    {
+      if (selectedIndex >= 0) 
+        return items.get(selectedIndex);
+      else
+        return null;
+    }
+    
+    /**
+     * Sets the selected item.  This clears all the directories from the
+     * existing list, and repopulates it with the new selected directory
+     * and all its parent directories.
+     * 
+     * @param selectedDirectory  the selected directory.
+     */
+    public void setSelectedItem(Object selectedDirectory)
+    {
+      items.clear();
+      FileSystemView fsv = getFileChooser().getFileSystemView();
+      File parent = (File) selectedDirectory;
+      while (parent != null)
+        {
+          items.add(0, parent);
+          parent = fsv.getParentDirectory(parent);
+        }
+      selectedIndex = items.indexOf(selectedDirectory);
+      fireContentsChanged(this, 0, items.size() - 1);
+    }
+    
+  }
+
+  /**
+   * Handles changes to the selection in the directory combo box.
+   */
+  protected class DirectoryComboBoxAction
+    extends AbstractAction
+  {
+    /**
+     * Creates a new action.
+     */
+    protected DirectoryComboBoxAction()
+    {
+      // Nothing to do here.
+    }
+    
+    /**
+     * Handles the action event.
+     * 
+     * @param e  the event.
+     */
+    public void actionPerformed(ActionEvent e)
+    {
+      JFileChooser fc = getFileChooser();
+      fc.setCurrentDirectory((File) directoryModel.getSelectedItem());
+    }
+  }
+
+  /**
+   * A renderer for the items in the directory combo box.
+   */
+  class DirectoryComboBoxRenderer
+    extends DefaultListCellRenderer
+  {
+    /**
+     * This is the icon that is displayed in the combobox. This wraps
+     * the standard icon and adds indendation.
+     */
+    private IndentIcon indentIcon;
+
+    /**
+     * Creates a new renderer.
+     */
+    public DirectoryComboBoxRenderer(JFileChooser fc)
+    {
+      indentIcon = new IndentIcon();
+    }
+    
+    /**
+     * Returns a component that can be used to paint the given value within 
+     * the list.
+     * 
+     * @param list  the list.
+     * @param value  the value (a {@link File}).
+     * @param index  the item index.
+     * @param isSelected  is the item selected?
+     * @param cellHasFocus  does the list cell have focus?
+     * 
+     * @return The list cell renderer.
+     */
+    public Component getListCellRendererComponent(JList list, Object value,
+                                                  int index,
+                                                  boolean isSelected,
+                                                  boolean cellHasFocus)
+    {
+      super.getListCellRendererComponent(list, value, index, isSelected,
+                                         cellHasFocus);
+      File file = (File) value;
+      setText(getFileChooser().getName(file));
+
+      // Install indented icon.
+      Icon icon = getFileChooser().getIcon(file);
+      indentIcon.setIcon(icon);
+      int depth = directoryModel.getDepth(index);
+      indentIcon.setDepth(depth);
+      setIcon(indentIcon);
+
+      return this;
+    }
+  }
+
+  /**
+   * An icon that wraps another icon and adds indentation.
+   */
+  class IndentIcon
+    implements Icon
+  {
+
+    /**
+     * The indentation level.
+     */
+    private static final int INDENT = 10;
+
+    /**
+     * The wrapped icon.
+     */
+    private Icon icon;
+
+    /**
+     * The current depth.
+     */
+    private int depth;
+
+    /**
+     * Sets the icon to be wrapped.
+     *
+     * @param i the icon
+     */
+    void setIcon(Icon i)
+    {
+      icon = i;
+    }
+
+    /**
+     * Sets the indentation depth.
+     *
+     * @param d the depth to set
+     */
+    void setDepth(int d)
+    {
+      depth = d;
+    }
+
+    public int getIconHeight()
+    {
+      return icon.getIconHeight();
+    }
+
+    public int getIconWidth()
+    {
+      return icon.getIconWidth() + depth * INDENT;
+    }
+
+    public void paintIcon(Component c, Graphics g, int x, int y)
+    {
+      icon.paintIcon(c, g, x + depth * INDENT, y);
+    }
+      
+  }
+
+  /**
+   * A renderer for the files and directories in the file chooser.
+   */
+  protected class FileRenderer
+    extends DefaultListCellRenderer
+  {
+    
+    /**
+     * Creates a new renderer.
+     */
+    protected FileRenderer()
+    {
+      // Nothing to do here.
+    }
+    
+    /**
+     * Returns a component that can render the specified value.
+     * 
+     * @param list  the list.
+     * @param value  the value (a {@link File}).
+     * @param index  the index.
+     * @param isSelected  is the item selected?
+     * @param cellHasFocus  does the item have the focus?
+     * 
+     * @return The renderer.
+     */
+    public Component getListCellRendererComponent(JList list, Object value,
+        int index, boolean isSelected, boolean cellHasFocus)
+    {
+      FileView v = getFileView(getFileChooser());
+      File f = (File) value;
+      if (f != null)
+        {
+          setText(v.getName(f));
+          setIcon(v.getIcon(f));
+        }
+      else
+        {
+          setText("");
+          setIcon(null);
+        }
+      setOpaque(true);
+      if (isSelected)
+        {
+          setBackground(list.getSelectionBackground());
+          setForeground(list.getSelectionForeground());
+        }
+      else
+        {
+          setBackground(list.getBackground());
+          setForeground(list.getForeground());
+        }
+
+      setEnabled(list.isEnabled());
+      setFont(list.getFont());
+
+      if (cellHasFocus)
+        setBorder(UIManager.getBorder("List.focusCellHighlightBorder"));
+      else
+        setBorder(noFocusBorder);
+      return this;
+    }
+  }
+
+  /**
+   * A combo box model for the file selection filters.
+   */
+  protected class FilterComboBoxModel
+    extends AbstractListModel
+    implements ComboBoxModel, PropertyChangeListener
+  {
+
+    /** Storage for the filters in the model. */
+    protected FileFilter[] filters;
+
+    /** The index of the selected file filter. */
+    private Object selected;
+    
+    /**
+     * Creates a new model.
+     */
+    protected FilterComboBoxModel()
+    {
+      filters = new FileFilter[1];
+      filters[0] = getAcceptAllFileFilter(getFileChooser());
+      selected = filters[0];
+    }
+    
+    /**
+     * Handles property changes.
+     * 
+     * @param e  the property change event.
+     */
+    public void propertyChange(PropertyChangeEvent e)
+    {
+      if (e.getPropertyName().equals(JFileChooser.FILE_FILTER_CHANGED_PROPERTY))
+        {
+          JFileChooser fc = getFileChooser();
+          FileFilter[] choosableFilters = fc.getChoosableFileFilters();
+          filters = choosableFilters;
+          fireContentsChanged(this, 0, filters.length);
+          selected = e.getNewValue();
+          fireContentsChanged(this, -1, -1);
+        }
+      else if (e.getPropertyName().equals(
+              JFileChooser.CHOOSABLE_FILE_FILTER_CHANGED_PROPERTY))
+        {
+          // repopulate list
+          JFileChooser fc = getFileChooser();
+          FileFilter[] choosableFilters = fc.getChoosableFileFilters();
+          filters = choosableFilters;
+          fireContentsChanged(this, 0, filters.length);
+        }
+    }
+    
+    /**
+     * Sets the selected filter.
+     * 
+     * @param filter  the filter (<code>null</code> ignored).
+     */
+    public void setSelectedItem(Object filter)
+    {
+      if (filter != null)
+      {
+          selected = filter;
+          fireContentsChanged(this, -1, -1);
+      }
+    }
+    
+    /**
+     * Returns the selected file filter.
+     * 
+     * @return The selected file filter.
+     */
+    public Object getSelectedItem()
+    {
+      return selected;
+    }
+    
+    /**
+     * Returns the number of items in the model.
+     * 
+     * @return The number of items in the model.
+     */
+    public int getSize()
+    {
+      return filters.length;
+    }
+    
+    /**
+     * Returns the item at the specified index.
+     * 
+     * @param index  the item index.
+     * 
+     * @return The item at the specified index.
+     */
+    public Object getElementAt(int index)
+    {
+      return filters[index];
+    }
+    
+  }
+
+  /**
+   * A renderer for the items in the file filter combo box.
+   */
+  public class FilterComboBoxRenderer
+    extends DefaultListCellRenderer
+  {
+    /**
+     * Creates a new renderer.
+     */
+    public FilterComboBoxRenderer()
+    {
+      // Nothing to do here.
+    }
+    
+    /**
+     * Returns a component that can be used to paint the given value within 
+     * the list.
+     * 
+     * @param list  the list.
+     * @param value  the value (a {@link FileFilter}).
+     * @param index  the item index.
+     * @param isSelected  is the item selected?
+     * @param cellHasFocus  does the list cell have focus?
+     * 
+     * @return This component as the renderer.
+     */
+    public Component getListCellRendererComponent(JList list, Object value,
+        int index, boolean isSelected, boolean cellHasFocus)
+    {
+      super.getListCellRendererComponent(list, value, index, isSelected, 
+                                         cellHasFocus);
+      FileFilter filter = (FileFilter) value;
+      setText(filter.getDescription());
+      return this;
+    }
+  }
+
+  /**
+   * A listener for selection events in the file list.
+   * 
+   * @see #createListSelectionListener(JFileChooser)
+   */
+  class MetalFileChooserSelectionListener 
+    implements ListSelectionListener
+  {
+    /**
+     * Creates a new <code>SelectionListener</code> object.
+     */
+    protected MetalFileChooserSelectionListener()
+    {
+      // Do nothing here.
+    }
+
+    /**
+     * Makes changes to different properties when
+     * a value has changed in the filechooser's selection.
+     *
+     * @param e - the list selection event that occured.
+     */
+    public void valueChanged(ListSelectionEvent e)
+    {
+      File f = (File) fileList.getSelectedValue();
+      if (f == null)
+        return;
+      JFileChooser filechooser = getFileChooser();
+      if (! filechooser.isTraversable(f))
+        filechooser.setSelectedFile(f);
+      else
+        filechooser.setSelectedFile(null);
+    }
+  }
+
+  /**
+   * A mouse listener for the {@link JFileChooser}.
+   * This listener is used for editing filenames.
+   */
+  protected class SingleClickListener
+    extends MouseAdapter
+  {
+    
+    /** Stores instance of the list */
+    JList list;
+    
+    /** 
+     * Stores the current file that is being edited.
+     * It is null if nothing is currently being edited.
+     */
+    File editFile;
+    
+    /** The current file chooser. */
+    JFileChooser fc;
+    
+    /** The last file selected. */
+    Object lastSelected;
+    
+    /** The textfield used for editing. */
+    JTextField editField;
+    
+    /**
+     * Creates a new listener.
+     * 
+     * @param list  the directory/file list.
+     */
+    public SingleClickListener(JList list)
+    {
+      this.list = list;
+      editFile = null;
+      fc = getFileChooser();
+      lastSelected = null;
+      startEditing = false;
+    }
+    
+    /**
+     * Receives notification of a mouse click event.
+     * 
+     * @param e  the event.
+     */
+    public void mouseClicked(MouseEvent e)
+    {
+      if (e.getClickCount() == 1 && e.getButton() == MouseEvent.BUTTON1)
+        {
+          int index = list.locationToIndex(e.getPoint());
+          File[] sf = fc.getSelectedFiles();
+          if ((!fc.isMultiSelectionEnabled() || (sf != null && sf.length <= 1))
+              && index >= 0 && !startEditing && list.isSelectedIndex(index))
+            {
+              Object tmp = list.getModel().getElementAt(index);
+              if (lastSelected != null && lastSelected.equals(tmp))
+                editFile(index);
+              lastSelected = tmp;
+            }
+          else
+              completeEditing();
+        }
+      else
+        completeEditing();
+    }
+    
+    /**
+     * Sets up the text editor for the current file.
+     * 
+     * @param index -
+     *          the current index of the item in the list to be edited.
+     */
+    void editFile(int index)
+    {
+      Rectangle bounds = list.getCellBounds(index, index);
+      list.scrollRectToVisible(bounds);
+      editFile = (File) list.getModel().getElementAt(index);
+      if (editFile.canWrite())
+        {
+          startEditing = true;
+          editField = new JTextField(editFile.getName());
+          editField.addActionListener(new EditingActionListener());
+          
+          Icon icon = getFileView(fc).getIcon(editFile);
+          if (icon != null)
+            {
+              int padding = icon.getIconWidth() + 4;
+              bounds.x += padding;
+              bounds.width -= padding;
+            }
+          editField.setBounds(bounds);
+          
+          list.add(editField);
+          
+          editField.requestFocus();
+          editField.selectAll();
+        }
+      else
+        completeEditing();
+      list.repaint();
+    }
+    
+    /** 
+     * Completes the editing.
+     */
+    void completeEditing()
+    {
+      if (editField != null && editFile != null)
+        {
+          String text = editField.getText();
+          if (text != null && text != "" && !text.equals(fc.getName(editFile)))
+	    {
+	      File f = fc.getFileSystemView().
+		createFileObject(fc.getCurrentDirectory(), text);
+              if ( editFile.renameTo(f) )
+                rescanCurrentDirectory(fc);
+	    }
+          list.remove(editField);
+        }
+      startEditing = false;
+      editFile = null;
+      lastSelected = null;
+      editField = null;
+      list.repaint();
+    }
+    
+    /**
+     * ActionListener for the editing text field.
+     */
+    class EditingActionListener implements ActionListener
+    {
+      
+      /**
+       * This method is invoked when an action occurs.
+       * 
+       * @param e -
+       *          the <code>ActionEvent</code> that occurred
+       */
+      public void actionPerformed(ActionEvent e)
+      {
+	if (editField != null)
+          completeEditing();
+      }
+    }
+  }
+
+  /**
+   * A mouse listener for the {@link JFileChooser}.
+   * This listener is used for the table
+   */
+  private class TableClickListener extends MouseAdapter
+  {
+
+    /** Stores instance of the table */
+    JTable table;
+
+    /** Stores instance of the file chooser */
+    JFileChooser fc;
+
+    /** The last selected file. */
+    Object lastSelected;
+    
+    /** 
+     * Stores the current file that is being edited.
+     * It is null if nothing is currently being edited.
+     */
+    File editFile;
+    
+    /** The textfield used for editing. */
+    JTextField editField;
+
+    /**
+     * Creates a new listener.
+     * 
+     * @param table the directory/file table
+     * @param fc the JFileChooser
+     */
+    public TableClickListener(JTable table, JFileChooser fc)
+    {
+      this.table = table;
+      this.fc = fc;
+      lastSelected = fileList.getSelectedValue();
+      setDirectorySelected(false);
+      startEditing = false;
+      editFile = null;
+      editField = null;
+    }
+
+    /**
+     * Receives notification of a mouse click event.
+     * 
+     * @param e the event.
+     */
+    public void mouseClicked(MouseEvent e)
+    {
+      int row = table.getSelectedRow();
+      Object selVal = fileList.getModel().getElementAt(row);
+      if (selVal == null)
+        return;
+      FileSystemView fsv = fc.getFileSystemView();
+      if (e.getClickCount() == 1 &&
+          selVal.equals(lastSelected) &&
+          e.getButton() == MouseEvent.BUTTON1)
+        {
+          File[] sf = fc.getSelectedFiles();
+          if ((!fc.isMultiSelectionEnabled() || (sf != null && sf.length <= 1))
+              && !startEditing)
+            {
+              editFile = (File) selVal;
+              editFile(row);
+            }
+        }
+      else if (e.getClickCount() >= 2 &&
+          selVal.equals(lastSelected))
+        {
+          if (startEditing)
+            completeEditing();
+          File f = fsv.createFileObject(lastSelected.toString());
+          if (fc.isTraversable(f))
+            {
+              fc.setCurrentDirectory(f);
+              fc.rescanCurrentDirectory();
+            }
+          else
+            {
+              fc.setSelectedFile(f);
+              fc.approveSelection();
+              closeDialog();
+            }
+        }
+      else
+        {
+          if (startEditing)
+            completeEditing();
+          String path = selVal.toString();
+          File f = fsv.createFileObject(path);
+          fc.setSelectedFile(f);
+          if (fc.isTraversable(f))
+            {
+              setDirectorySelected(true);
+              setDirectory(f);
+            }
+          else
+            {
+              setDirectorySelected(false);
+              setDirectory(null);
+            }
+          lastSelected = selVal;
+          if (f.isFile())
+            setFileName(path.substring(path.lastIndexOf("/") + 1));
+          else if (fc.getFileSelectionMode() != JFileChooser.FILES_ONLY)
+            setFileName(path);
+        }
+      fileTable.repaint();
+    }
+
+    /**
+     * Sets up the text editor for the current file.
+     * 
+     * @param row -
+     *          the current row of the item in the list to be edited.
+     */
+    void editFile(int row)
+    {
+      Rectangle bounds = table.getCellRect(row, 0, true);
+      table.scrollRectToVisible(bounds);
+      if (editFile.canWrite())
+        {
+          startEditing = true;
+          editField = new JTextField(editFile.getName());
+          editField.addActionListener(new EditingActionListener());
+
+          // Need to adjust y pos
+          bounds.y = row * table.getRowHeight();
+          editField.setBounds(bounds);
+          
+          table.add(editField);
+          
+          editField.requestFocus();
+          editField.selectAll();
+        }
+      else
+        completeEditing();
+      table.repaint();
+    }
+    
+    /** 
+     * Completes the editing.
+     */
+    void completeEditing()
+    {
+      if (editField != null && editFile != null)
+        {
+          String text = editField.getText();
+          if (text != null && text != "" && !text.equals(fc.getName(editFile)))
+              if (editFile.renameTo(fc.getFileSystemView().createFileObject(
+                  fc.getCurrentDirectory(), text)))
+                rescanCurrentDirectory(fc);
+          table.remove(editField);
+        }
+      startEditing = false;
+      editFile = null;
+      editField = null;
+      table.repaint();
+    }
+    
+    /**
+     * ActionListener for the editing text field.
+     */
+    class EditingActionListener implements ActionListener
+    {
+      
+      /**
+       * This method is invoked when an action occurs.
+       * 
+       * @param e -
+       *          the <code>ActionEvent</code> that occurred
+       */
+      public void actionPerformed(ActionEvent e)
+      {
+	if (editField != null)
+          completeEditing();
+      }
+    }
+    
+    /**
+     * Closes the dialog.
+     */
+    public void closeDialog()
+    {
+      Window owner = SwingUtilities.windowForComponent(fc);
+      if (owner instanceof JDialog)
+        ((JDialog) owner).dispose();
+    }
+  } 
+  
+  /** The text for a label describing the directory combo box. */
+  private String directoryLabel;
+  
+  private JComboBox directoryComboBox;
+  
+  /** The model for the directory combo box. */
+  DirectoryComboBoxModel directoryModel;
+  
+  /** The text for a label describing the file text field. */
+  private String fileLabel;
+  
+  /** The file name text field. */
+  private JTextField fileTextField;
+  
+  /** The text for a label describing the filter combo box. */
+  private String filterLabel;
+
+  /** 
+   * The top panel (contains the directory combo box and the control buttons). 
+   */
+  private JPanel topPanel;
+  
+  /** A panel containing the control buttons ('up', 'home' etc.). */
+  private JPanel controls;
+
+  /** 
+   * The panel that contains the filename field and the filter combobox. 
+   */
+  private JPanel bottomPanel;
+
+  /** 
+   * The panel that contains the 'Open' (or 'Save') and 'Cancel' buttons. 
+   */
+  private JPanel buttonPanel;
+  
+  private JButton approveButton;
+  
+  /** The file list. */
+  JList fileList;
+  
+  /** The file table. */
+  JTable fileTable;
+  
+  /** The panel containing the file list. */
+  JPanel fileListPanel;
+  
+  /** The panel containing the file table. */
+  JPanel fileTablePanel;
+  
+  /** The filter combo box model. */
+  private FilterComboBoxModel filterModel;
+
+  /** The action map. */
+  private ActionMap actionMap;
+  
+  /** True if currently in list view. */
+  boolean listView;
+  
+  /** True if we can or have started editing a cell. */
+  boolean startEditing;
+  
+  /** The scrollpane used for the table and list. */
+  JScrollPane scrollPane;
+  
+  /** The text for the label when saving. */
+  String save;
+  
+  /** The text for the label when opening a directory. */
+  String look;
+  
+  /** The label for the file combo box. */
+  JLabel dirLabel;
+  
+  /** Listeners. */
+  ListSelectionListener listSelList;
+  MouseListener doubleClickList;
+  SingleClickListener singleClickList;
+  TableClickListener tableClickList;
+  
+  /**
+   * A factory method that returns a UI delegate for the specified
+   * component.
+   * 
+   * @param c  the component (which should be a {@link JFileChooser}).
+   */
+  public static ComponentUI createUI(JComponent c)
+  {
+    JFileChooser chooser = (JFileChooser) c;
+    return new MetalFileChooserUI(chooser);
+  }
+
+  /**
+   * Creates a new instance of this UI delegate.
+   * 
+   * @param filechooser  the file chooser component.
+   */
+  public MetalFileChooserUI(JFileChooser filechooser)
+  {
+    super(filechooser);
+    bottomPanel = new JPanel(new GridLayout(3, 2));
+    buttonPanel = new JPanel();
+  }
+
+  public void installUI(JComponent c)
+  {
+    super.installUI(c);
+    actionMap = createActionMap();
+  }
+  
+  public void uninstallUI(JComponent c)
+  {
+    super.uninstallUI(c);
+    actionMap = null;
+  }
+  
+  /**
+   * Installs the sub-components of the file chooser.
+   * 
+   * @param fc  the file chooser component.
+   */
+  public void installComponents(JFileChooser fc)
+  {
+    fc.setLayout(new BorderLayout());
+    topPanel = new JPanel(new BorderLayout());
+    dirLabel = new JLabel(directoryLabel);
+    topPanel.add(dirLabel, BorderLayout.WEST);
+    this.controls = new JPanel();
+    addControlButtons();
+    
+    JPanel dirPanel = new JPanel(new VerticalMidLayout());
+    directoryModel = createDirectoryComboBoxModel(fc);
+    directoryComboBox = new JComboBox(directoryModel);
+    directoryComboBox.setRenderer(createDirectoryComboBoxRenderer(fc));
+    dirPanel.add(directoryComboBox);
+    topPanel.add(dirPanel);
+    topPanel.add(controls, BorderLayout.EAST);
+    topPanel.setBorder(BorderFactory.createEmptyBorder(8, 8, 0, 8));
+    fc.add(topPanel, BorderLayout.NORTH);
+    
+    JPanel list = createList(fc);
+    list.setBorder(BorderFactory.createEmptyBorder(8, 8, 8, 8));
+    fc.add(list, BorderLayout.CENTER);
+    
+    JPanel bottomPanel = getBottomPanel();
+    filterModel = createFilterComboBoxModel();
+    JComboBox fileFilterCombo = new JComboBox(filterModel);
+    fileFilterCombo.setRenderer(createFilterComboBoxRenderer());
+    
+    fileTextField = new JTextField();
+    JPanel fileNamePanel = new JPanel(new VerticalMidLayout());
+    fileNamePanel.setBorder(BorderFactory.createEmptyBorder(0, 20, 0, 5));
+    fileNamePanel.add(fileTextField);
+    JPanel row1 = new JPanel(new BorderLayout());
+    row1.add(new JLabel(this.fileLabel), BorderLayout.WEST);
+    row1.add(fileNamePanel);
+    bottomPanel.add(row1);
+    
+    JPanel row2 = new JPanel(new BorderLayout());
+    row2.add(new JLabel(this.filterLabel), BorderLayout.WEST);
+    row2.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 5));
+    row2.add(fileFilterCombo);
+    bottomPanel.add(row2);
+    JPanel buttonPanel = new JPanel(new ButtonLayout());
+    
+    approveButton = new JButton(getApproveSelectionAction());
+    approveButton.setText(getApproveButtonText(fc));
+    approveButton.setToolTipText(getApproveButtonToolTipText(fc));
+    approveButton.setMnemonic(getApproveButtonMnemonic(fc));
+    buttonPanel.add(approveButton);
+    buttonPanel.setBorder(BorderFactory.createEmptyBorder(8, 0, 0, 0));
+    
+    JButton cancelButton = new JButton(getCancelSelectionAction());
+    cancelButton.setText(cancelButtonText);
+    cancelButton.setToolTipText(cancelButtonToolTipText);
+    cancelButton.setMnemonic(cancelButtonMnemonic);
+    buttonPanel.add(cancelButton);
+    bottomPanel.add(buttonPanel, BorderLayout.SOUTH);
+    bottomPanel.setBorder(BorderFactory.createEmptyBorder(0, 8, 8, 8));
+    fc.add(bottomPanel, BorderLayout.SOUTH);
+    
+    fc.add(getAccessoryPanel(), BorderLayout.EAST);
+  }
+  
+  /**
+   * Uninstalls the components added by 
+   * {@link #installComponents(JFileChooser)}.
+   * 
+   * @param fc  the file chooser.
+   */
+  public void uninstallComponents(JFileChooser fc)
+  {
+    fc.remove(bottomPanel);
+    bottomPanel = null;
+    fc.remove(fileListPanel);
+    fc.remove(fileTablePanel);
+    fileTablePanel = null;
+    fileListPanel = null;
+    fc.remove(topPanel);
+    topPanel = null;
+    
+    directoryModel = null;
+    fileTextField = null;
+    directoryComboBox = null;
+  }
+  
+  /**
+   * Returns the panel that contains the 'Open' (or 'Save') and 'Cancel' 
+   * buttons.
+   * 
+   * @return The panel.
+   */
+  protected JPanel getButtonPanel()
+  {
+    return buttonPanel;    
+  }
+  
+  /**
+   * Creates and returns a new panel that will be used for the controls at
+   * the bottom of the file chooser.
+   * 
+   * @return A new panel.
+   */
+  protected JPanel getBottomPanel()
+  {
+    if (bottomPanel == null)
+      bottomPanel = new JPanel(new GridLayout(3, 2));
+    return bottomPanel;
+  }
+  
+  /**
+   * Fetches localised strings for use by the labels and buttons on the
+   * file chooser.
+   * 
+   * @param fc  the file chooser.
+   */
+  protected void installStrings(JFileChooser fc)
+  { 
+     super.installStrings(fc);
+     look = "Look In: ";
+     save = "Save In: ";
+     if (fc.getDialogType() == JFileChooser.SAVE_DIALOG)
+       directoryLabel = save;
+     else
+       directoryLabel = look;
+     
+     fileLabel = "File Name: ";
+     filterLabel = "Files of Type: ";
+     
+     this.cancelButtonMnemonic = 0;
+     this.cancelButtonText = "Cancel";
+     this.cancelButtonToolTipText = "Abort file chooser dialog";
+     
+     this.directoryOpenButtonMnemonic = 0;
+     this.directoryOpenButtonText = "Open";
+     this.directoryOpenButtonToolTipText = "Open selected directory";
+     
+     this.helpButtonMnemonic = 0;
+     this.helpButtonText = "Help";
+     this.helpButtonToolTipText = "Filechooser help";
+     
+     this.openButtonMnemonic = 0;
+     this.openButtonText = "Open";
+     this.openButtonToolTipText = "Open selected file";
+     
+     this.saveButtonMnemonic = 0;
+     this.saveButtonText = "Save";
+     this.saveButtonToolTipText = "Save selected file";
+     
+     this.updateButtonMnemonic = 0;
+     this.updateButtonText = "Update";
+     this.updateButtonToolTipText = "Update directory listing";   
+  }
+  
+  /**
+   * Installs the listeners required.
+   * 
+   * @param fc  the file chooser.
+   */
+  protected void installListeners(JFileChooser fc)
+  {
+    directoryComboBox.setAction(new DirectoryComboBoxAction());
+    fc.addPropertyChangeListener(filterModel);
+    listSelList = createListSelectionListener(fc);
+    doubleClickList = this.createDoubleClickListener(fc, fileList);
+    singleClickList = new SingleClickListener(fileList);
+    fileList.addListSelectionListener(listSelList);
+    fileList.addMouseListener(doubleClickList);
+    fileList.addMouseListener(singleClickList);
+    super.installListeners(fc);
+  }
+  
+  protected void uninstallListeners(JFileChooser fc) 
+  {
+    super.uninstallListeners(fc);
+    fc.removePropertyChangeListener(filterModel);
+    directoryComboBox.setAction(null);
+    fileList.removeListSelectionListener(listSelList);
+    fileList.removeMouseListener(doubleClickList);
+    fileList.removeMouseListener(singleClickList);
+    
+    if (fileTable != null)
+      fileTable.removeMouseListener(tableClickList);
+  }
+  
+  protected ActionMap getActionMap()
+  {
+    if (actionMap == null)
+      actionMap = createActionMap();
+    return actionMap;
+  }
+  
+  /**
+   * Creates and returns an action map.
+   * 
+   * @return The action map.
+   */
+  protected ActionMap createActionMap()
+  {
+    ActionMap map = new ActionMap();
+    map.put("approveSelection", getApproveSelectionAction());
+    map.put("cancelSelection", getCancelSelectionAction());
+    map.put("Go Up", getChangeToParentDirectoryAction());
+    return map;
+  }
+
+  /**
+   * Creates a panel containing a list of files.
+   * 
+   * @param fc  the file chooser.
+   * 
+   * @return A panel.
+   */
+  protected JPanel createList(JFileChooser fc)
+  {
+    if (fileList == null)
+      {
+        fileListPanel = new JPanel(new BorderLayout());
+        fileList = new JList(getModel());
+        scrollPane = new JScrollPane(fileList);
+        fileList.setLayoutOrientation(JList.VERTICAL_WRAP);
+        fileList.setCellRenderer(new FileRenderer());
+      }
+    else
+      {
+        fileList.setModel(getModel());
+        fileListPanel.removeAll();
+        scrollPane.getViewport().setView(fileList);
+      }
+    fileListPanel.add(scrollPane);
+    // This size was determined using BeanShell and dumping the JFileChooser
+    // component hierarchy. Sun has an internal FilePane class in there, but
+    // that probably doesn't matter atm.
+    fileListPanel.setPreferredSize(new Dimension(405, 135));
+    return fileListPanel;
+  }
+  
+  /**
+   * Creates a panel containing a table within a scroll pane.
+   * 
+   * @param fc  the file chooser.
+   * 
+   * @return The details view.
+   */
+  protected JPanel createDetailsView(JFileChooser fc)
+  {
+    fileTablePanel = new JPanel(new BorderLayout());
+    
+    Object[] cols = new Object[] {"Name", "Size", "Modified"};
+    Object[][] rows = new Object[fileList.getModel().getSize()][3];
+    
+    fileTable = new JTable(new DefaultTableModel(rows, cols));
+    
+    if (fc.isMultiSelectionEnabled())
+      fileTable.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
+    else
+      fileTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+    
+    fileTable.setShowGrid(false);
+    fileTable.setColumnSelectionAllowed(false);
+    fileTable.setDefaultRenderer(Object.class, new TableFileRenderer());
+
+    tableClickList = new TableClickListener(fileTable, fc);
+    fileTable.addMouseListener(tableClickList);
+    
+    return updateTable();  
+  }
+  
+  /**
+   * Sets the values in the table, and puts it in the panel.
+   * 
+   * @return the panel containing the table.
+   */
+  JPanel updateTable()
+  {
+    DefaultTableModel mod = (DefaultTableModel) fileTable.getModel();
+    ListModel lm = fileList.getModel();
+    DateFormat dt = DateFormat.getDateTimeInstance(DateFormat.SHORT,
+                                                   DateFormat.SHORT);
+    File curr = null;
+    int size = lm.getSize();
+    int rc = mod.getRowCount();
+
+    // If there are not enough rows
+    for (int x = rc; x < size; x++)
+      mod.addRow(new Object[3]);
+
+    for (int i = 0; i < size; i++)
+      {
+        curr = (File) lm.getElementAt(i);
+        fileTable.setValueAt(curr.getName(), i, 0);
+        fileTable.setValueAt(formatSize(curr.length()), i, 1);
+        fileTable.setValueAt(dt.format(new Date(curr.lastModified())), i, 2);
+      }
+
+    // If there are too many rows
+    while (rc > size)
+      mod.removeRow(--rc);
+
+    scrollPane.getViewport().setView(fileTable);
+    scrollPane.setColumnHeaderView(fileTable.getTableHeader());
+
+    fileTablePanel.removeAll();
+    fileTablePanel.add(scrollPane);
+
+    return fileTablePanel;
+  }
+  
+  /**
+   * Formats bytes into the appropriate size.
+   * 
+   * @param bytes the number of bytes to convert
+   * @return a string representation of the size
+   */
+  private String formatSize(long bytes)
+  {
+    NumberFormat nf = NumberFormat.getNumberInstance();
+    long mb = (long) Math.pow(2, 20);
+    long kb = (long) Math.pow(2, 10);
+    long gb = (long) Math.pow(2, 30);
+    double size = 0;
+    String id = "";
+    
+    if ((bytes / gb) >= 1)
+      {
+        size = (double) bytes / (double) gb;
+        id = "GB";
+      }
+    else if ((bytes / mb) >= 1)
+      {
+        size = (double) bytes / (double) mb;
+        id = "MB";
+      }
+    else if ((bytes / kb) >= 1)
+      {
+        size = (double) bytes / (double) kb;
+        id = "KB";
+      }
+    else
+      {
+        size = bytes;
+        id = "Bytes";
+      }
+    
+    return nf.format(size) + " " + id;
+  }
+  /**
+   * Creates a listener that monitors selections in the directory/file list
+   * and keeps the {@link JFileChooser} component up to date.
+   * 
+   * @param fc  the file chooser.
+   * 
+   * @return The listener.
+   * 
+   * @see #installListeners(JFileChooser)
+   */
+  public ListSelectionListener createListSelectionListener(JFileChooser fc)
+  {
+    return new MetalFileChooserSelectionListener();
+  }
+  
+  /**
+   * Returns the preferred size for the file chooser component.
+   * 
+   * @return The preferred size.
+   */
+  public Dimension getPreferredSize(JComponent c)
+  {
+    Dimension tp = topPanel.getPreferredSize();
+    Dimension bp = bottomPanel.getPreferredSize();
+    Dimension fl = fileListPanel.getPreferredSize();
+    return new Dimension(fl.width, tp.height + bp.height + fl.height);
+  }
+
+  /**
+   * Returns the minimum size for the file chooser component.
+   * 
+   * @return The minimum size.
+   */
+  public Dimension getMinimumSize(JComponent c)
+  {
+    Dimension tp = topPanel.getMinimumSize();
+    Dimension bp = bottomPanel.getMinimumSize();
+    Dimension fl = fileListPanel.getMinimumSize();
+    return new Dimension(fl.width, tp.height + bp.height + fl.height);
+  }
+  
+  /**
+   * Returns the maximum size for the file chooser component.
+   * 
+   * @return The maximum size.
+   */
+  public Dimension getMaximumSize(JComponent c)
+  {
+    return new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE);
+  }
+  
+  /**
+   * Creates a property change listener that monitors the {@link JFileChooser}
+   * for property change events and updates the component display accordingly.
+   * 
+   * @param fc  the file chooser.
+   * 
+   * @return The property change listener.
+   * 
+   * @see #installListeners(JFileChooser)
+   */
+  public PropertyChangeListener createPropertyChangeListener(JFileChooser fc)
+  {
+    return new MetalFileChooserPropertyChangeListener();
+  }
+
+  /**
+   * Creates and returns a new instance of {@link DirectoryComboBoxModel}.
+   * 
+   * @return A new instance of {@link DirectoryComboBoxModel}.
+   */
+  protected MetalFileChooserUI.DirectoryComboBoxModel 
+      createDirectoryComboBoxModel(JFileChooser fc)
+  {
+    return new DirectoryComboBoxModel();
+  }
+
+  /**
+   * Creates a new instance of the renderer used in the directory
+   * combo box.
+   * 
+   * @param fc  the file chooser.
+   * 
+   * @return The renderer.
+   */
+  protected DirectoryComboBoxRenderer createDirectoryComboBoxRenderer(
+          JFileChooser fc)
+  {
+    return new DirectoryComboBoxRenderer(fc);
+  }
+
+  /**
+   * Creates and returns a new instance of {@link FilterComboBoxModel}.
+   * 
+   * @return A new instance of {@link FilterComboBoxModel}.
+   */
+  protected FilterComboBoxModel createFilterComboBoxModel()
+  {
+    return new FilterComboBoxModel();  
+  }
+
+  /**
+   * Creates and returns a new instance of {@link FilterComboBoxRenderer}.
+   * 
+   * @return A new instance of {@link FilterComboBoxRenderer}.
+   */
+  protected MetalFileChooserUI.FilterComboBoxRenderer 
+      createFilterComboBoxRenderer()
+  {
+    return new FilterComboBoxRenderer(); 
+  }
+
+  /**
+   * Adds the control buttons ('up', 'home' etc.) to the panel.
+   */
+  protected void addControlButtons()
+  {
+    JButton upButton = new JButton(getChangeToParentDirectoryAction());
+    upButton.setText(null);
+    upButton.setIcon(this.upFolderIcon);
+    upButton.setMargin(new Insets(0, 0, 0, 0));
+    controls.add(upButton);
+    
+    JButton homeButton = new JButton(getGoHomeAction());
+    homeButton.setText(null);
+    homeButton.setIcon(this.homeFolderIcon);
+    homeButton.setMargin(new Insets(0, 0, 0, 0));
+    controls.add(homeButton);
+    
+    JButton newFolderButton = new JButton(getNewFolderAction());
+    newFolderButton.setText(null);
+    newFolderButton.setIcon(this.newFolderIcon);
+    newFolderButton.setMargin(new Insets(0, 0, 0, 0));
+    controls.add(newFolderButton);
+    
+    JToggleButton listButton = new JToggleButton(this.listViewIcon);
+    listButton.setMargin(new Insets(0, 0, 0, 0));
+    listButton.addActionListener(new ListViewActionListener());
+    listButton.setSelected(true);
+    listView = true; 
+    controls.add(listButton);
+    
+    JToggleButton detailButton = new JToggleButton(this.detailsViewIcon);
+    detailButton.setMargin(new Insets(0, 0, 0, 0));
+    detailButton.addActionListener(new DetailViewActionListener());
+    detailButton.setSelected(false);
+    controls.add(detailButton);
+
+    ButtonGroup buttonGroup = new ButtonGroup();
+    buttonGroup.add(listButton);
+    buttonGroup.add(detailButton);
+  }
+  
+  /**
+   * Removes all the buttons from the control panel.
+   */
+  protected void removeControlButtons()
+  {
+    controls.removeAll();
+    controls.revalidate();
+    controls.repaint();
+  }
+  
+  /**
+   * Updates the current directory.
+   * 
+   * @param fc  the file chooser to update.
+   */
+  public void rescanCurrentDirectory(JFileChooser fc)
+  {
+    directoryModel.setSelectedItem(fc.getCurrentDirectory());
+    getModel().validateFileCache();
+    if (!listView)
+        updateTable();
+    else
+      createList(fc);
+  }
+  
+  /**
+   * Returns the file name in the text field.
+   * 
+   * @return The file name.
+   */
+  public String getFileName()
+  {
+    String result = null;
+    if (fileTextField != null) 
+      result = fileTextField.getText();
+    return result;
+  }
+  
+  /**
+   * Sets the file name in the text field.
+   * 
+   * @param filename  the file name.
+   */
+  public void setFileName(String filename)
+  {
+    fileTextField.setText(filename);
+  }
+  
+  /**
+   * DOCUMENT ME!!
+   * 
+   * @param e - DOCUMENT ME!
+   */
+  public void valueChanged(ListSelectionEvent e)
+  {
+    // FIXME: Not sure what we should be doing here, if anything.
+  }
+  
+  /**
+   * Returns the approve button.
+   * 
+   * @return The approve button.
+   */
+  protected JButton getApproveButton(JFileChooser fc)
+  {
+    return approveButton;
+  }
+
+  /**
+   * A layout manager that is used to arrange the subcomponents of the
+   * {@link JFileChooser}.
+   */
+  class VerticalMidLayout implements LayoutManager
+  {
+    /**
+     * Performs the layout.
+     * 
+     * @param parent  the container.
+     */
+    public void layoutContainer(Container parent) 
+    {
+      int count = parent.getComponentCount();
+      if (count > 0)
+        {
+          Insets insets = parent.getInsets();
+          Component c = parent.getComponent(0);
+          Dimension prefSize = c.getPreferredSize();
+          int h = parent.getHeight() - insets.top - insets.bottom;
+          int adj = Math.max(0, (h - prefSize.height) / 2);
+          c.setBounds(insets.left, insets.top + adj, parent.getWidth() 
+              - insets.left - insets.right, 
+              (int) Math.min(prefSize.getHeight(), h));
+        }
+    }
+    
+    /**
+     * Returns the minimum layout size.
+     * 
+     * @param parent  the container.
+     * 
+     * @return The minimum layout size.
+     */
+    public Dimension minimumLayoutSize(Container parent) 
+    {
+      return preferredLayoutSize(parent);
+    }
+    
+    /**
+     * Returns the preferred layout size.
+     * 
+     * @param parent  the container.
+     * 
+     * @return The preferred layout size.
+     */
+    public Dimension preferredLayoutSize(Container parent) 
+    {
+      if (parent.getComponentCount() > 0)
+        {
+          return parent.getComponent(0).getPreferredSize();
+        }
+      else return null;
+    }
+    
+    /**
+     * This layout manager does not need to track components, so this 
+     * method does nothing.
+     * 
+     * @param name  the name the component is associated with.
+     * @param component  the component.
+     */
+    public void addLayoutComponent(String name, Component component) 
+    {
+      // do nothing
+    }
+    
+    /**
+     * This layout manager does not need to track components, so this 
+     * method does nothing.
+     * 
+     * @param component  the component.
+     */
+    public void removeLayoutComponent(Component component) 
+    {
+      // do nothing
+    }
+  }
+
+  /**
+   * A layout manager that is used to arrange buttons for the
+   * {@link JFileChooser}.
+   */
+  class ButtonLayout implements LayoutManager
+  {
+    static final int GAP = 4;
+      
+    /**
+     * Performs the layout.
+     * 
+     * @param parent  the container.
+     */
+    public void layoutContainer(Container parent) 
+    {
+      int count = parent.getComponentCount();
+      if (count > 0)
+        {
+          // first find the widest button
+          int maxW = 0;
+          for (int i = 0; i < count; i++)
+            {
+              Component c = parent.getComponent(i);
+              Dimension prefSize = c.getPreferredSize();
+              maxW = Math.max(prefSize.width, maxW);
+            }
+  
+          // then position the buttons
+          Insets insets = parent.getInsets();
+          int availableH = parent.getHeight() - insets.top - insets.bottom;
+          int currentX = parent.getWidth() - insets.right;
+          for (int i = count - 1; i >= 0; i--)
+            {
+              Component c = parent.getComponent(i);
+              Dimension prefSize = c.getPreferredSize();      
+              int adj = Math.max(0, (availableH - prefSize.height) / 2);
+              currentX = currentX - prefSize.width;
+              c.setBounds(currentX, insets.top + adj, prefSize.width, 
+                  (int) Math.min(prefSize.getHeight(), availableH));
+              currentX = currentX - GAP;
+            }
+        }
+    }
+    
+    /**
+     * Returns the minimum layout size.
+     * 
+     * @param parent  the container.
+     * 
+     * @return The minimum layout size.
+     */
+    public Dimension minimumLayoutSize(Container parent) 
+    {
+      return preferredLayoutSize(parent);
+    }
+    
+    /**
+     * Returns the preferred layout size.
+     * 
+     * @param parent  the container.
+     * 
+     * @return The preferred layout size.
+     */
+    public Dimension preferredLayoutSize(Container parent) 
+    {
+      Insets insets = parent.getInsets();
+      int maxW = 0;
+      int maxH = 0;
+      int count = parent.getComponentCount();
+      if (count > 0) 
+        {
+          for (int i = 0; i < count; i++)
+            {
+              Component c = parent.getComponent(i);
+              Dimension d = c.getPreferredSize();
+              maxW = Math.max(d.width, maxW);
+              maxH = Math.max(d.height, maxH);
+            }
+        }
+      return new Dimension(maxW * count + GAP * (count - 1) + insets.left 
+              + insets.right, maxH + insets.top + insets.bottom);
+    }
+    
+    /**
+     * This layout manager does not need to track components, so this 
+     * method does nothing.
+     * 
+     * @param name  the name the component is associated with.
+     * @param component  the component.
+     */
+    public void addLayoutComponent(String name, Component component) 
+    {
+      // do nothing
+    }
+    
+    /**
+     * This layout manager does not need to track components, so this 
+     * method does nothing.
+     * 
+     * @param component  the component.
+     */
+    public void removeLayoutComponent(Component component) 
+    {
+      // do nothing
+    }
+  }
+
+}





More information about the llvm-commits mailing list