OSDN Git Service

missing added files from merge
authorgraydon <graydon@138bc75d-0d04-0410-961f-82ee72b054a4>
Thu, 2 Sep 2004 06:58:08 +0000 (06:58 +0000)
committergraydon <graydon@138bc75d-0d04-0410-961f-82ee72b054a4>
Thu, 2 Sep 2004 06:58:08 +0000 (06:58 +0000)
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@86958 138bc75d-0d04-0410-961f-82ee72b054a4

30 files changed:
libjava/gnu/java/awt/peer/gtk/GThreadMutex.java [new file with mode: 0644]
libjava/gnu/java/awt/peer/gtk/GThreadNativeMethodRunner.java [new file with mode: 0644]
libjava/javax/swing/AbstractSpinnerModel.java [new file with mode: 0644]
libjava/javax/swing/JSpinner.java [new file with mode: 0644]
libjava/javax/swing/SpinnerNumberModel.java [new file with mode: 0644]
libjava/javax/swing/TransferHandler.java [new file with mode: 0644]
libjava/javax/swing/colorchooser/DefaultHSBChooserPanel.java [new file with mode: 0644]
libjava/javax/swing/colorchooser/DefaultPreviewPanel.java [new file with mode: 0644]
libjava/javax/swing/colorchooser/DefaultRGBChooserPanel.java [new file with mode: 0644]
libjava/javax/swing/colorchooser/DefaultSwatchChooserPanel.java [new file with mode: 0644]
libjava/javax/swing/plaf/basic/BasicColorChooserUI.java [new file with mode: 0644]
libjava/javax/swing/plaf/basic/BasicComboBoxEditor.java [new file with mode: 0644]
libjava/javax/swing/plaf/basic/BasicComboBoxRenderer.java [new file with mode: 0644]
libjava/javax/swing/plaf/basic/BasicComboBoxUI.java [new file with mode: 0644]
libjava/javax/swing/plaf/basic/BasicComboPopup.java [new file with mode: 0644]
libjava/javax/swing/plaf/basic/BasicFormattedTextFieldUI.java [new file with mode: 0644]
libjava/javax/swing/plaf/basic/BasicPasswordFieldUI.java [new file with mode: 0644]
libjava/javax/swing/plaf/basic/BasicSpinnerUI.java [new file with mode: 0644]
libjava/javax/swing/plaf/basic/BasicTableHeaderUI.java [new file with mode: 0644]
libjava/javax/swing/plaf/basic/BasicTableUI.java [new file with mode: 0644]
libjava/javax/swing/plaf/basic/BasicTextAreaUI.java [new file with mode: 0644]
libjava/javax/swing/plaf/basic/BasicToolTipUI.java [new file with mode: 0644]
libjava/javax/swing/plaf/basic/ComboPopup.java [new file with mode: 0644]
libjava/javax/swing/text/SimpleAttributeSet.java [new file with mode: 0644]
libjava/javax/swing/text/StyleConstants.java [new file with mode: 0644]
libjava/javax/swing/text/StyleContext.java [new file with mode: 0644]
libjava/javax/swing/text/TabSet.java [new file with mode: 0644]
libjava/javax/swing/text/TabStop.java [new file with mode: 0644]
libjava/javax/swing/text/Utilities.java [new file with mode: 0644]
libjava/jni/gtk-peer/gnu_java_awt_peer_gtk_GThreadNativeMethodRunner.c [new file with mode: 0644]

diff --git a/libjava/gnu/java/awt/peer/gtk/GThreadMutex.java b/libjava/gnu/java/awt/peer/gtk/GThreadMutex.java
new file mode 100644 (file)
index 0000000..111c9a8
--- /dev/null
@@ -0,0 +1,109 @@
+/* GThreadMutex.java -- Implements a mutex object for glib's gthread
+   abstraction, for use with GNU Classpath's --portable-native-sync option.
+   This is used in gthread-jni.c
+   
+   Copyright (C) 2004 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.java.awt.peer.gtk;
+
+/** Implements a mutex object for glib's gthread
+    abstraction, for use with GNU Classpath's --portable-native-sync option.
+    This is used in gthread-jni.c.
+
+    We use this object to implement the POSIX semantics for Mutexes.  They are
+    needed are needed for the function vector that is passed to glib's
+    g_thread subpackage's initialization function.
+
+    The GThreadMutex object itself serves as the Real Lock; if code has
+    entered the monitor for this GThreadMutex object (in Java language, if
+    it's synchronized on this object) then it holds the lock that this object
+    represents.
+
+    @author Steven Augart
+    May, 2004
+
+    
+*/
+   
+class GThreadMutex 
+{
+  /** Might "lock" be locked?  Is anyone waiting
+      to get that lock?  How long is the queue?
+
+      If zero, nobody holds a lock on this GThreadMutex object, and nobody is
+      trying to get one.   Before someone attempts to acquire a lock on this
+      object, they must increment potentialLockers.  After they release their
+      lock on this object, they must decrement potentialLockers.
+
+      Access to this field is guarded by synchronizing on the object
+      <code>lockForPotentialLockers</code>.
+
+      After construction, we only access this field via JNI.
+  */
+  volatile int potentialLockers;
+
+  /** An object to synchronize to if you want to examine or modify the
+      <code>potentialLockers</code> field.  Only hold this lock for brief
+      moments, just long enough to check or set the value of
+      <code>lockForPotentialLockers</code>.  
+      
+      We use this representation so that g_thread_mutex_trylock() will work
+      with the POSIX semantics.  This is the only case in which you ever hold a
+      lock on <code>lockForPotentialLockers</code> while trying to get another
+      lock -- if you are the mutex_trylock() implementation, and you have just
+      checked that <code>potentialLockers</code> has the value zero.  In that
+      case, mutex_trylock() holds the lock on lockForPotentialLockers so that
+      another thread calling mutex_trylock() or mutex_lock() won't increment
+      potentialLockers after we've checked it and before we've gained the lock
+      on the POSIX mutex.   Of course, in that case the operation of gaining
+      the POSIX lock itself will succeed immediately, and once it has
+      succeeded, trylock releases lockForPotentialLockers right away,
+      incremented to 1 (one).
+
+      After construction, we only access this field via JNI.
+  */     
+  Object lockForPotentialLockers;
+
+  GThreadMutex() 
+  {
+    potentialLockers = 0;
+    lockForPotentialLockers = new Object();
+  }
+}
+// Local Variables:
+// c-file-style: "gnu"
+// End:
diff --git a/libjava/gnu/java/awt/peer/gtk/GThreadNativeMethodRunner.java b/libjava/gnu/java/awt/peer/gtk/GThreadNativeMethodRunner.java
new file mode 100644 (file)
index 0000000..a4cb35a
--- /dev/null
@@ -0,0 +1,302 @@
+/* GThreadNativeMethodRunner.java -- Implements pthread_create(), under
+   glib's gthread abstraction, for use with GNU Classpath's
+   --portable-native-sync option. 
+   This is used by gthread-jni.c
+   
+   Copyright (C) 2004 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.java.awt.peer.gtk;
+import java.lang.ref.WeakReference;
+import java.util.Set;
+import java.util.Collections;
+import java.util.HashSet;
+
+/** Implements pthread_create(), under glib's gthread abstraction, for use
+    with GNU Classpath's --portable-native-sync option.  This is used in
+    gthread-jni.c
+
+    Also implements a registry for threads, mapping Thread objects to small
+    integers.  The registry uses weak references for threads that aren't
+    joinable, so that they will be garbage collected.
+
+    There are a number of possible alternative implementations.
+    
+    
+    The rest of this comment consists of an answer to a question that was
+    raised on the commit-classpath mailing list:
+
+    Mark Wielaard wrote:
+
+    > Can't we assume that jobject and gpointer are both (void *) so we don't
+    > need the int <-> Thread (global jobject ref) mapping?
+    > Maybe there are platforms where jobject and gpointer aren't the same,
+    > but I guess that is pretty unlikely.
+
+
+    I agree with you on the pointer size issues.  A gpointer is a void *, so
+    it's certainly guaranteed to be at least as large as any other
+    pointer. And a jobject is implicitly an opaque pointer (in Jikes RVM, we
+    use small integers, but we coerce them into the representation of a
+    pointer).
+
+    The int <==> Thread mapping addresses a different issue.  I realize that I
+    did not document this properly (two and a half lines in thread_create),
+    and the point is subtle (at least to me; took me a while to figure out).
+
+    The int => Thread mapping always returns jobjects that are local
+    references, not global ones.  This is because Thread objects need to be
+    able to go away and be garbage collected after the thread they refer to
+    has died.
+
+    If we keep a global object reference to a thread, then when do we delete
+    that global object reference?  We have an answer in the case of GThread
+    objects that were explicitly created with the joinable attribute.  It is
+    safe for us to maintain a global reference to any joinable thread, since
+    the joinable thread must linger (even if only in a zombie state)
+    until it's explicitly joined via a g_thread_join() call.  The global ref
+    could be cleaned up at that point too.
+
+    However, in the case of GThreads that were created non-joinable by
+    g_thread_create(), and in the case of Java threads that were created
+    within pure Java code (not via g_thread_create()), we don't want them to
+    linger forever, and there is no way to tell when the last reference
+    to such threads needs to expire.  In the case of this application -- AWT
+    with GTK peers -- it would probably be safe anyway, since there are not
+    very many threads we create, but I was going for correctness even in the
+    case of long-running programs that might set up and tear down AWT
+    interfaces many times.
+
+    So, I duplicated the POSIX thread-ID semantics.  The thread ID of a
+    non-joinable thread remains valid as long as that thread is still alive.
+    Once that thread dies, the old thread ID may be reused at any moment.  And
+    that's why the array indexed by thread ID numbers is an array of weak
+    references.
+
+    That's also why the int => Thread jobject mapping function always returns
+    local references, since global references would lock the Thread in memory
+    forever.
+
+    I would dearly love there to be a cleaner solution.  I dislike the
+    repeated dips from C code into Java that are necessary to look up thread
+    ID numbers.  If anyone can think of one, I'm all ears.
+*/
+
+class GThreadNativeMethodRunner 
+  extends Thread 
+{
+  /** The C function pointer that was passed to g_thread_create().
+      Specifically, this the numeric address of an object of 
+      C type "void *(*funcPtr)(void *funcArg)".   
+  */
+  private final long funcPtr;
+
+  /** The argument for the function "funcPtr(funcArg)". */
+  private final long funcArg;
+  
+  GThreadNativeMethodRunner(long funcPtr, long funcArg, boolean joinable) 
+  {
+    this.funcPtr = funcPtr;
+    this.funcArg = funcArg;
+
+    if (joinable)
+      registerSelfJoinable();
+  }
+
+  public void run() 
+  {
+    nativeRun(funcPtr, funcArg);
+  }
+
+  private native void nativeRun(long funcPtr, long funcArg);
+
+  /** THREADS is an array of threads, indexed by thread ID codes.  Not sure
+      whether this is the "best" approach but it does make it O(1) to look up a
+      thread by its ID. 
+
+      Zero is a valid thread ID code.  Any negative number is invalid.
+
+      Possible future fixes (TODO?)
+
+     - The THREADS array will only grow. probably not a problem.
+        But we could keep count when nulling entries and shrink when we have
+        lots of nulls at the end. Probably not worth it. --mjw
+
+     - Could make this a set of Object; see the comment on "joinable" below.
+
+     The initial size of 17 is just a starting point.  Any number will do,
+     including zero.
+  */ 
+  private static WeakReference[] threads = new WeakReference[17]; 
+
+  /**  Used by threadToThreadID, below.  Returns the registration number of
+       the newly-registered thread.  
+  */
+  private static synchronized int registerThread(Thread t) 
+  {
+    int i;
+
+    for (i = 0; i < threads.length; ++i) 
+      {
+       WeakReference ref = threads[i];
+       if (ref == null)
+         break;                  // found an empty spot.
+      }
+
+    if (i == threads.length) 
+      {
+       /* expand the array */
+       WeakReference[] bigger = new WeakReference[threads.length * 2];
+        System.arraycopy(threads, 0, bigger, 0, threads.length);
+       threads = bigger;
+      }
+
+    threads[i] = new WeakReference(t);
+
+    return i;
+  }
+  
+  /**  Look up the Thread ID # for a Thread.  Assign a Thread ID # if none
+       exists.  This is a general routine for handling all threads, including
+       the VM's main thread, if appropriate.
+
+
+       Runs in O(n/2) time.
+
+       We can't just issue a threadID upon thread creation.  If we were to do
+       that, not all threads would have a threadID, because not all threads
+       are launched by GThreadNativeMethodRunner.
+  */ 
+  static synchronized int threadToThreadID(Thread t) 
+  {
+    for (int i = 0; i < threads.length; ++i ) 
+      {
+       if (threads[i] == null)
+         continue;
+       Thread referent = (Thread) threads[i].get();
+       if (referent == null) 
+         {
+           threads[i] = null;      // Purge the dead WeakReference.
+           continue;
+         }
+       if (referent.equals(t))
+         return i;
+      } // for()
+
+    /* No match found. */
+    return registerThread(t);
+  }
+
+  /** @param threadID Must be a non-negative integer.
+
+      Used to return null if the thread number was out of range or if
+      the thread was unregistered.   Now we throw an exception.
+
+      Possible Alternative Interface:  We could go back to returning null in
+           some sort of check-free mode, so code that calls this function must
+           be prepared to get null. 
+  */ 
+  static Thread threadIDToThread(int threadID) 
+    throws IllegalArgumentException
+  {
+    if (threadID < 0)
+      throw new IllegalArgumentException("Received a negative threadID, " 
+                                        + threadID); 
+    if (threadID >= threads.length)
+      throw new IllegalArgumentException("Received a threadID (" + threadID 
+                                        + ") higher than was" 
+                                        + " ever issued"); 
+    
+    /* Note: if the user is using a stale reference, things will just
+       break.    We might end up getting a different thread than the one
+       expected. 
+       
+       TODO: Add an error-checking mode where the user's problems with threads
+          are announced.  For instance, if the user asks for the thread
+          associated with a threadID that was never issued, we could print a
+          warning or even abort.
+       
+       TODO: Consider optionally disabling all of the error-checking we
+          already have; it probably slows down the implementation.  We could
+          just return NULL.  This is just the reverse of the above TODO item.
+    */ 
+
+    WeakReference threadRef = threads[threadID];
+
+    if (threadRef == null)
+      throw new IllegalArgumentException("Asked to look up a stale or unissued"
+                                        + "threadID (" + threadID + ")" );
+    
+      
+    Thread referent = (Thread) threadRef.get();
+    if (referent == null)
+      throw new IllegalArgumentException ("Asked to look up a stale threadID ("
+                                         + threadID + ")");
+    return referent;
+  }
+  
+  /** Joinable threads need a hard reference, so that they won't go away when
+      they die.  That is because their thread IDs need to stay valid until the
+      thread is joined via thread_join(threadID).  Joinable threads have to be
+      explicitly joined before they are allowed to go away completely.
+
+      Possible Alternative Implementation: Eliminate the Joinable set.  When
+          calling getThreadIDFromThread() you know whether or not the thread
+          is joinable.  So just store the Thread itself in the threads array?
+          Make that array an Object array and check with instanceof.  This
+          looks cleaner and more robust to me and it saves a native -> Java
+          call. But instanceof might be expensive.  --mjw
+  */
+  private static final Set joinable = 
+       Collections.synchronizedSet(new HashSet()); 
+  
+  /** Only called from the constructor. */
+  private void registerSelfJoinable() 
+  {
+    joinable.add(this);
+  }
+  
+  /** This method is only called from JNI, and only after we have succeeded in
+      a thread_join() operation.  */
+  static void deRegisterJoinable(Thread thread) 
+  {
+    joinable.remove(thread);
+  }
+}
+\f
+// Local Variables:
+// c-file-style: "gnu"
+// End:
diff --git a/libjava/javax/swing/AbstractSpinnerModel.java b/libjava/javax/swing/AbstractSpinnerModel.java
new file mode 100644 (file)
index 0000000..d2d345b
--- /dev/null
@@ -0,0 +1,115 @@
+/* AbstractSpinnerModel.java --
+   Copyright (C) 2004 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+package javax.swing;
+
+import java.util.EventListener;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+import javax.swing.event.EventListenerList;
+
+/**
+ * AbstractSpinnerModel
+ * @author     Ka-Hing Cheung
+ * @version    1.0
+ */
+public abstract class AbstractSpinnerModel implements SpinnerModel
+{
+  private ChangeEvent changeEvent = new ChangeEvent(this);
+  
+  protected EventListenerList listenerList = new EventListenerList();
+
+  /**
+   * Creates an <code>AbstractSpinnerModel</code>.
+   */
+  public AbstractSpinnerModel()
+  {
+  }
+
+  /**
+   * Adds a <code>ChangeListener</code>.
+   *
+   * @param listener the listener to add
+   */
+  public void addChangeListener(ChangeListener listener)
+  {
+    listenerList.add(ChangeListener.class, listener);
+  }
+
+  /**
+   * Gets all the listeners that are of a particular type.
+   *
+   * @param c the type of listener
+   * @return the listeners that are of the specific type
+   */
+  public EventListener[] getListeners(Class c)
+  {
+    return listenerList.getListeners(c);
+  }
+
+  /**
+   * Gets all the <code>ChangeListener</code>s.
+   *
+   * @return all the <code>ChangeListener</code>s
+   */
+  public ChangeListener[] getChangeListeners()
+  {
+    return (ChangeListener[]) listenerList.getListeners(ChangeListener.class);
+  }
+
+  /**
+   * Remove a particular listener.
+   *
+   * @param listener the listener to remove
+   */
+  public void removeChangeListener(ChangeListener listener)
+  {
+    listenerList.remove(ChangeListener.class, listener);
+  }
+
+  /**
+   * Fires a <code>ChangeEvent</code> to all the <code>ChangeListener</code>s
+   * added to this model
+   */
+  protected void fireStateChanged()
+  {
+    ChangeListener[] listeners = getChangeListeners();
+
+    for(int i = 0; i < listeners.length; ++i)
+      listeners[i].stateChanged(changeEvent);
+  }
+}
diff --git a/libjava/javax/swing/JSpinner.java b/libjava/javax/swing/JSpinner.java
new file mode 100644 (file)
index 0000000..00b22d5
--- /dev/null
@@ -0,0 +1,482 @@
+/* JSpinner.java --
+   Copyright (C) 2004 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+package javax.swing;
+
+import java.awt.BorderLayout;
+import java.awt.Component;
+import java.awt.Container;
+import java.awt.Dimension;
+import java.awt.LayoutManager;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+import java.text.DecimalFormat;
+import java.text.ParseException;
+import java.util.EventListener;
+import javax.swing.border.EtchedBorder;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+import javax.swing.event.EventListenerList;
+import javax.swing.plaf.SpinnerUI;
+
+
+/**
+ * A JSpinner is a component which typically contains a numeric value and a
+ * way to manipulate the value.
+ *
+ * @author Ka-Hing Cheung
+ * @version 1.0
+ */
+public class JSpinner extends JComponent
+{
+  /**
+   * DOCUMENT ME!
+   */
+  public static class StubEditor extends JLabel implements ChangeListener
+  {
+    /** DOCUMENT ME! */
+    private JLabel label;
+
+    /** DOCUMENT ME! */
+    private JButton up;
+
+    /** DOCUMENT ME! */
+    private JButton down;
+
+    /** DOCUMENT ME! */
+    private JSpinner spinner;
+
+    /**
+     * Creates a new StubEditor object.
+     *
+     * @param spinner DOCUMENT ME!
+     */
+    public StubEditor(JSpinner spinner)
+    {
+      this.spinner = spinner;
+      setBorder(new EtchedBorder());
+      setHorizontalAlignment(SwingConstants.TRAILING);
+      stateChanged(null); /* fill in the label */
+    }
+
+    /**
+     * DOCUMENT ME!
+     *
+     * @param evt DOCUMENT ME!
+     */
+    public void stateChanged(ChangeEvent evt)
+    {
+      setText(String.valueOf(spinner.getValue()));
+    }
+  }
+
+  /**
+   * DOCUMENT ME!
+   */
+  public static class DefaultEditor extends JPanel implements ChangeListener,
+                                                              PropertyChangeListener,
+                                                              LayoutManager
+  {
+    /**
+     * Creates a new DefaultEditor object.
+     *
+     * @param spinner DOCUMENT ME!
+     */
+    public DefaultEditor(JSpinner spinner)
+    {
+      spinner.addChangeListener(this);
+    } /* TODO */
+    /**
+     * DOCUMENT ME!
+     */
+    public void commitEdit()
+    {
+    } /* TODO */
+    /**
+     * DOCUMENT ME!
+     *
+     * @param spinner DOCUMENT ME!
+     */
+    public void dismiss(JSpinner spinner)
+    {
+      spinner.removeChangeListener(this);
+    }
+
+    /**
+     * DOCUMENT ME!
+     *
+     * @return DOCUMENT ME!
+     */
+    public JFormattedTextField getTextField()
+    {
+      return null;
+    } /* TODO */
+    /**
+     * DOCUMENT ME!
+     *
+     * @param parent DOCUMENT ME!
+     */
+    public void layoutContainer(Container parent)
+    {
+    } /* TODO */
+    /**
+     * DOCUMENT ME!
+     *
+     * @param parent DOCUMENT ME!
+     *
+     * @return DOCUMENT ME!
+     */
+    public Dimension minimumLayoutSize(Container parent)
+    {
+      return null;
+    } /* TODO */
+    /**
+     * DOCUMENT ME!
+     *
+     * @param parent DOCUMENT ME!
+     *
+     * @return DOCUMENT ME!
+     */
+    public Dimension preferredLayoutSize(Container parent)
+    {
+      return null;
+    } /* TODO */
+    /**
+     * DOCUMENT ME!
+     *
+     * @param evt DOCUMENT ME!
+     */
+    public void propertyChange(PropertyChangeEvent evt)
+    {
+    } /* TODO */
+    /**
+     * DOCUMENT ME!
+     *
+     * @param evt DOCUMENT ME!
+     */
+    public void stateChanged(ChangeEvent evt)
+    {
+    } /* TODO */
+    /* no-ops */
+    public void removeLayoutComponent(Component child)
+    {
+    }
+
+    /**
+     * DOCUMENT ME!
+     *
+     * @param name DOCUMENT ME!
+     * @param child DOCUMENT ME!
+     */
+    public void addLayoutComponent(String name, Component child)
+    {
+    }
+  }
+
+  /**
+   * DOCUMENT ME!
+   */
+  public static class NumberEditor extends DefaultEditor
+  {
+    /**
+     * Creates a new NumberEditor object.
+     *
+     * @param spinner DOCUMENT ME!
+     */
+    public NumberEditor(JSpinner spinner)
+    {
+      super(spinner);
+    }
+
+    /**
+     * DOCUMENT ME!
+     *
+     * @return DOCUMENT ME!
+     */
+    public DecimalFormat getFormat()
+    {
+      return null;
+    }
+  }
+
+  /** DOCUMENT ME! */
+  private SpinnerModel model;
+
+  /** DOCUMENT ME! */
+  private JComponent editor;
+
+  /** DOCUMENT ME! */
+  private EventListenerList listenerList = new EventListenerList();
+
+  /** DOCUMENT ME! */
+  private ChangeListener listener = new ChangeListener()
+    {
+      public void stateChanged(ChangeEvent evt)
+      {
+       fireStateChanged();
+      }
+    };
+
+  /**
+   * Creates a JSpinner with <code>SpinnerNumberModel</code>
+   *
+   * @see javax.swing.SpinnerNumberModel
+   */
+  public JSpinner()
+  {
+    this(new SpinnerNumberModel());
+  }
+
+  /**
+   * Creates a JSpinner with the specific model and sets the default editor
+   *
+   * @param model DOCUMENT ME!
+   */
+  public JSpinner(SpinnerModel model)
+  {
+    this.model = model;
+    model.addChangeListener(listener);
+    setEditor(createEditor(model));
+    updateUI();
+  }
+
+  /**
+   * If the editor is <code>JSpinner.DefaultEditor</code>, then forwards the
+   * call to it, otherwise do nothing.
+   *
+   * @throws ParseException DOCUMENT ME!
+   */
+  public void commitEdit() throws ParseException
+  {
+    if (editor instanceof DefaultEditor)
+      ((DefaultEditor) editor).commitEdit();
+  }
+
+  /**
+   * Gets the current editor
+   *
+   * @return the current editor
+   *
+   * @see #setEditor
+   */
+  public JComponent getEditor()
+  {
+    return editor;
+  }
+
+  /**
+   * Changes the current editor to the new editor. This methods should remove
+   * the old listeners (if any) and adds the new listeners (if any).
+   *
+   * @param editor the new editor
+   *
+   * @throws IllegalArgumentException DOCUMENT ME!
+   *
+   * @see #getEditor
+   */
+  public void setEditor(JComponent editor)
+  {
+    if (editor == null)
+      throw new IllegalArgumentException("editor may not be null");
+
+    if (this.editor instanceof DefaultEditor)
+      ((DefaultEditor) editor).dismiss(this);
+    else if (this.editor instanceof ChangeListener)
+      removeChangeListener((ChangeListener) this.editor);
+
+    if (editor instanceof ChangeListener)
+      addChangeListener((ChangeListener) editor);
+
+    this.editor = editor;
+  }
+
+  /**
+   * Gets the underly model.
+   *
+   * @return the underly model
+   */
+  public SpinnerModel getModel()
+  {
+    return model;
+  }
+
+  /**
+   * Gets the next value without changing the current value.
+   *
+   * @return the next value
+   *
+   * @see javax.swing.SpinnerModel#getNextValue
+   */
+  public Object getNextValue()
+  {
+    return model.getNextValue();
+  }
+
+  /**
+   * Gets the previous value without changing the current value.
+   *
+   * @return the previous value
+   *
+   * @see javax.swing.SpinnerModel#getPreviousValue
+   */
+  public Object getPreviousValue()
+  {
+    return model.getPreviousValue();
+  }
+
+  /**
+   * Gets the <code>SpinnerUI</code> that handles this spinner
+   *
+   * @return the <code>SpinnerUI</code>
+   */
+  public SpinnerUI getUI()
+  {
+    return (SpinnerUI) ui;
+  }
+
+  /**
+   * Gets the current value of the spinner, according to the underly model,
+   * not the UI.
+   *
+   * @return the current value
+   *
+   * @see javax.swing.SpinnerModel#getValue
+   */
+  public Object getValue()
+  {
+    return model.getValue();
+  }
+
+  /**
+   * DOCUMENT ME!
+   *
+   * @param value DOCUMENT ME!
+   */
+  public void setValue(Object value)
+  {
+    model.setValue(value);
+  }
+
+  /**
+   * This method returns a name to identify which look and feel class will be
+   * the UI delegate for this spinner.
+   *
+   * @return The UIClass identifier. "SpinnerUI"
+   */
+  public String getUIClassID()
+  {
+    return "SpinnerUI";
+  }
+
+  /**
+   * This method resets the spinner's UI delegate to the default UI for the
+   * current look and feel.
+   */
+  public void updateUI()
+  {
+    setUI((SpinnerUI) UIManager.getUI(this));
+  }
+
+  /**
+   * This method sets the spinner's UI delegate.
+   *
+   * @param ui The spinner's UI delegate.
+   */
+  public void setUI(SpinnerUI ui)
+  {
+    super.setUI(ui);
+  }
+
+  /**
+   * Adds a <code>ChangeListener</code>
+   *
+   * @param listener the listener to add
+   */
+  public void addChangeListener(ChangeListener listener)
+  {
+    listenerList.add(ChangeListener.class, listener);
+  }
+
+  /**
+   * Remove a particular listener
+   *
+   * @param listener the listener to remove
+   */
+  public void removeChangeListener(ChangeListener listener)
+  {
+    listenerList.remove(ChangeListener.class, listener);
+  }
+
+  /**
+   * Gets all the <code>ChangeListener</code>s
+   *
+   * @return all the <code>ChangeListener</code>s
+   */
+  public ChangeListener[] getChangeListeners()
+  {
+    return (ChangeListener[]) listenerList.getListeners(ChangeListener.class);
+  }
+
+  /**
+   * Fires a <code>ChangeEvent</code> to all the <code>ChangeListener</code>s
+   * added to this <code>JSpinner</code>
+   */
+  protected void fireStateChanged()
+  {
+    ChangeEvent evt = new ChangeEvent(this);
+    ChangeListener[] listeners = getChangeListeners();
+
+    for (int i = 0; i < listeners.length; ++i)
+      listeners[i].stateChanged(evt);
+  }
+
+  /**
+   * Creates an editor for this <code>JSpinner</code>. Really, it should be a
+   * <code>JSpinner.DefaultEditor</code>, but since that should be
+   * implemented by a JFormattedTextField, and one is not written, I am just
+   * using a dummy one backed by a JLabel.
+   *
+   * @param model DOCUMENT ME!
+   *
+   * @return the default editor
+   */
+  protected JComponent createEditor(SpinnerModel model)
+  {
+    return new StubEditor(this);
+  } /* TODO */}
diff --git a/libjava/javax/swing/SpinnerNumberModel.java b/libjava/javax/swing/SpinnerNumberModel.java
new file mode 100644 (file)
index 0000000..18588b5
--- /dev/null
@@ -0,0 +1,241 @@
+/* SpinnerNumberModel.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., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+package javax.swing;
+
+/**
+ * SpinnerNumberModel
+ *
+ * @author Ka-Hing Cheung
+ * @version 1.0
+ */
+public class SpinnerNumberModel extends AbstractSpinnerModel
+{
+  /** DOCUMENT ME! */
+  private Number value;
+
+  /** DOCUMENT ME! */
+  private Comparable minimum;
+
+  /** DOCUMENT ME! */
+  private Comparable maximum;
+
+  /** DOCUMENT ME! */
+  private Number stepSize;
+
+  /**
+   * Creates a <code>SpinnerNumberModel</code> with initial value 0, step 1,
+   * and no maximum nor minimum.
+   */
+  public SpinnerNumberModel()
+  {
+    this(new Integer(0), null, null, new Integer(1));
+  }
+
+  /**
+   * Creates a <code>SpinnerNumberModel</code> with double precision
+   *
+   * @param value the initial value
+   * @param minimum the minimum value
+   * @param maximum the maximum value
+   * @param stepSize the step size
+   */
+  public SpinnerNumberModel(double value, double minimum, double maximum,
+                            double stepSize)
+  {
+    this(new Double(value), new Double(minimum), new Double(maximum),
+         new Double(stepSize));
+  }
+
+  /**
+   * Creates a <code>SpinnerNumberModel</code> with integer precision
+   *
+   * @param value the initial value
+   * @param minimum the minimum value
+   * @param maximum the maximum value
+   * @param stepSize the step size
+   */
+  public SpinnerNumberModel(int value, int minimum, int maximum, int stepSize)
+  {
+    this(new Integer(value), new Integer(minimum), new Integer(maximum),
+         new Integer(stepSize));
+  }
+
+  /**
+   * Creates a <code>SpinnerNumberModel</code> with <code>Number</code>s and
+   * <code>Comparable</code>s.
+   *
+   * @param value the initial value
+   * @param minimum the minimum value, if null there's no minimum
+   * @param maximum the maximum value, if null there's no maximum
+   * @param stepSize the step size
+   *
+   * @throws IllegalArgumentException if minimum &lt;= value &lt;= maximum
+   *         does not hold
+   */
+  public SpinnerNumberModel(Number value, Comparable minimum,
+                            Comparable maximum, Number stepSize)
+  {
+    if (stepSize == null)
+      throw new IllegalArgumentException("stepSize may not be null");
+    if (value == null)
+      throw new IllegalArgumentException("value may not be null");
+    if (minimum != null)
+      {
+       if (minimum.compareTo(value) > 0)
+         throw new IllegalArgumentException("minimum is not <= value");
+      }
+    else
+      minimum = new Comparable()
+         {
+           public int compareTo(Object obj)
+           {
+             return -1;
+           }
+         };
+
+
+    if (maximum != null)
+      {
+       if (maximum.compareTo(value) < 0)
+         throw new IllegalArgumentException("maximum is not >= value");
+      }
+    else
+      maximum = new Comparable()
+         {
+           public int compareTo(Object obj)
+           {
+             return 1;
+           }
+         };
+
+
+    this.value = value;
+    this.stepSize = stepSize;
+    this.minimum = minimum;
+    this.maximum = maximum;
+  }
+
+  /**
+   * Sets the new value and fire a change event
+   *
+   * @param value the new value
+   *
+   * @throws IllegalArgumentException if minimum &lt;= value &lt;= maximum
+   *         does not hold
+   */
+  public void setValue(Object value)
+  {
+    if (! (value instanceof Number))
+      throw new IllegalArgumentException("value must be a Number");
+
+    this.value = (Number) value;
+    fireStateChanged();
+  }
+
+  /**
+   * Gets the current value
+   *
+   * @return the current value
+   */
+  public Object getValue()
+  {
+    return value;
+  }
+
+  /**
+   * Gets the next value without changing the current value, or null if the
+   * current value is maximum.
+   *
+   * @return the next value
+   */
+  public Object getNextValue()
+  {
+    Number num;
+
+    if (value instanceof Double)
+      num = new Double(value.doubleValue() + stepSize.doubleValue());
+    else if (value instanceof Float)
+      num = new Double(value.floatValue() + stepSize.floatValue());
+    else if (value instanceof Long)
+      num = new Long(value.longValue() + stepSize.longValue());
+    else if (value instanceof Integer)
+      num = new Integer(value.intValue() + stepSize.intValue());
+    else if (value instanceof Short)
+      num = new Short((short) (value.shortValue() + stepSize.shortValue()));
+    else
+      num = new Byte((byte) (value.byteValue() + stepSize.byteValue()));
+
+    return maximum.compareTo(num) >= 0 ? num : null;
+  }
+
+  /**
+   * Gets the previous value without changing the current value, or null if
+   * the current value is minimum.
+   *
+   * @return the previous value
+   */
+  public Object getPreviousValue()
+  {
+    Number num;
+
+    if (value instanceof Double)
+      num = new Double(value.doubleValue() - stepSize.doubleValue());
+    else if (value instanceof Float)
+      num = new Double(value.floatValue() - stepSize.floatValue());
+    else if (value instanceof Long)
+      num = new Long(value.longValue() - stepSize.longValue());
+    else if (value instanceof Integer)
+      num = new Integer(value.intValue() - stepSize.intValue());
+    else if (value instanceof Short)
+      num = new Short((short) (value.shortValue() - stepSize.shortValue()));
+    else
+      num = new Byte((byte) (value.byteValue() - stepSize.byteValue()));
+
+    return minimum.compareTo(num) <= 0 ? num : null;
+  }
+
+  /**
+   * DOCUMENT ME!
+   *
+   * @return DOCUMENT ME!
+   */
+  public Number getNumber()
+  {
+    return value;
+  }
+}
diff --git a/libjava/javax/swing/TransferHandler.java b/libjava/javax/swing/TransferHandler.java
new file mode 100644 (file)
index 0000000..e64df9c
--- /dev/null
@@ -0,0 +1,55 @@
+/* TransferHandler.java --
+   Copyright (C) 2004 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+package javax.swing;
+
+import java.io.Serializable;
+
+public class TransferHandler implements Serializable
+{
+  private static final long serialVersionUID = -7908749299918704233L;
+
+  public static final int NONE = 0;
+  public static final int COPY = 1;
+  public static final int MOVE = 2;
+  public static final int COPY_OR_MOVE = 3;
+
+  protected TransferHandler()
+  {
+    // Do nothing here.
+  }
+}
diff --git a/libjava/javax/swing/colorchooser/DefaultHSBChooserPanel.java b/libjava/javax/swing/colorchooser/DefaultHSBChooserPanel.java
new file mode 100644 (file)
index 0000000..dcd795a
--- /dev/null
@@ -0,0 +1,860 @@
+/* DefaultHSBChooserPanel.java --
+   Copyright (C) 2004 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+package javax.swing.colorchooser;
+
+import java.awt.BorderLayout;
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.ComponentOrientation;
+import java.awt.Container;
+import java.awt.Dimension;
+import java.awt.Graphics;
+import java.awt.GridLayout;
+import java.awt.Image;
+import java.awt.LayoutManager;
+import java.awt.Point;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseMotionListener;
+import java.awt.image.MemoryImageSource;
+import javax.swing.AbstractButton;
+import javax.swing.ButtonGroup;
+import javax.swing.Icon;
+import javax.swing.JColorChooser;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JRadioButton;
+import javax.swing.JSlider;
+import javax.swing.JSpinner;
+import javax.swing.SpinnerNumberModel;
+import javax.swing.SwingConstants;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+
+
+/**
+ * This is the Default HSB Panel displayed in the JColorChooser.
+ */
+class DefaultHSBChooserPanel extends AbstractColorChooserPanel
+{
+  /** The gradient image displayed. */
+  private transient Image gradientImage;
+
+  /** The Panel that holds the gradient image. */
+  private transient JPanel gradientPanel;
+
+  /** The track gradient image. */
+  private transient Image trackImage;
+
+  /** The panel that holds the track. */
+  private transient JPanel trackPanel;
+
+  /** The slider for the locked HSB value. */
+  private transient JSlider slider;
+
+  /** The RadioButton that controls the Hue. */
+  private transient JRadioButton hRadio;
+
+  /** The RadioButton that controls the Saturation. */
+  private transient JRadioButton sRadio;
+
+  /** The RadioButton that controls the Brightness. */
+  private transient JRadioButton bRadio;
+
+  /** The JSpinner that controls the Hue. */
+  private transient JSpinner hSpinner;
+
+  /** The JSpinner that controls the Saturation. */
+  private transient JSpinner sSpinner;
+
+  /** The JSpinner that controls the Brightness. */
+  private transient JSpinner bSpinner;
+
+  /** The default width of the gradient image. */
+  private static final int imgWidth = 200;
+
+  /** The default height of the gradient image. */
+  private static final int imgHeight = 200;
+
+  /** The default width of the track gradient. */
+  private static final int trackWidth = 30;
+
+  /** The JLabel for Red. */
+  private static final JLabel R = new JLabel("R");
+
+  /** The JLabel for Green. */
+  private static final JLabel G = new JLabel("G");
+
+  /** The JLabel for Blue. */
+  private static final JLabel B = new JLabel("B");
+
+  // FIXME: Should be textfields.
+
+  /** The JLabel that displays the value of Red. */
+  private transient JLabel rFull;
+
+  /** The JLabel that displays the value of Green. */
+  private transient JLabel gFull;
+
+  /** The JLabel that displays the value of Blue. */
+  private transient JLabel bFull;
+
+  /** The point that is displayed in the gradient image. */
+  private transient Point gradientPoint = new Point();
+
+  /**
+   * This indicates that the change to the slider or point is triggered
+   * internally.
+   */
+  private transient boolean internalChange = false;
+
+  /** This indicates that the change to the spinner is triggered internally. */
+  private transient boolean spinnerTrigger = false;
+
+  /** This int identifies which spinner is currently locked. */
+  private transient int locked = -1;
+
+  /** This value indicates that the Hue spinner is locked. */
+  static final int HLOCKED = 0;
+
+  /** This value indicates that the Saturation spinner is locked. */
+  static final int SLOCKED = 1;
+
+  /** This value indicates that the Brightness spinner is locked. */
+  static final int BLOCKED = 2;
+
+  /**
+   * This method indicates that the mouse event is in the process of being
+   * handled.
+   */
+  private transient boolean handlingMouse;
+
+  /**
+   * This helper class handles mouse events on the gradient image.
+   */
+  class MainGradientMouseListener extends MouseAdapter
+    implements MouseMotionListener
+  {
+    /**
+     * This method is called when the mouse is pressed over the gradient
+     * image. The JColorChooser is then updated with new HSB values.
+     *
+     * @param e The MouseEvent.
+     */
+    public void mousePressed(MouseEvent e)
+    {
+      gradientPoint = e.getPoint();
+      update(e.getPoint());
+    }
+
+    /**
+     * This method is called when the mouse is dragged over the gradient
+     * image. The JColorChooser is then updated with the new HSB values.
+     *
+     * @param e The MouseEvent.
+     */
+    public void mouseDragged(MouseEvent e)
+    {
+      Point p = e.getPoint();
+      if (p.x < 0 || p.y < 0 || p.y > imgHeight || p.x > imgWidth)
+       return;
+
+      gradientPoint = p;
+      update(p);
+    }
+
+    /**
+     * This method is called when the mouse is moved over the gradient image.
+     *
+     * @param e The MouseEvent.
+     */
+    public void mouseMoved(MouseEvent e)
+    {
+      // Do nothing.
+    }
+
+    /**
+     * This method updates the JColorChooser with the new values.
+     *
+     * @param p The Point where the MouseEvent occurred.
+     */
+    private void update(Point p)
+    {
+      handlingMouse = true;
+      if (hSpinner.isEnabled())
+       updateH(p);
+      else if (sSpinner.isEnabled())
+       updateS(p);
+      else
+       updateB(p);
+      handlingMouse = false;
+    }
+
+    /**
+     * This method updates the SB values if Hue is locked.
+     *
+     * @param p The point where the MouseEvent occurred.
+     */
+    private void updateH(Point p)
+    {
+      float s = (imgWidth - p.x * 1f) / imgWidth;
+      float b = (imgHeight - p.y * 1f) / imgHeight;
+
+      // Avoid two changes to the model by changing internalChange to true.
+      internalChange = true;
+      sSpinner.setValue(new Integer((int) (s * 100)));
+      internalChange = false;
+      bSpinner.setValue(new Integer((int) (b * 100)));
+
+      revalidate();
+    }
+
+    /**
+     * This method updates the HB values if Saturation is locked.
+     *
+     * @param p The point where the MouseEvent occurred.
+     */
+    private void updateS(Point p)
+    {
+      float h = p.x * 1f / imgWidth;
+      float b = (imgHeight - p.y * 1f) / imgHeight;
+
+      internalChange = true;
+      hSpinner.setValue(new Integer((int) (h * 365)));
+      internalChange = false;
+      bSpinner.setValue(new Integer((int) (b * 100)));
+
+      revalidate();
+    }
+
+    /**
+     * This method updates the HS values if Brightness is locked.
+     *
+     * @param p The point where the MouseEvent occurred.
+     */
+    private void updateB(Point p)
+    {
+      float h = p.x * 1f / imgWidth;
+      float s = (imgHeight - p.y * 1f) / imgHeight;
+
+      internalChange = true;
+      hSpinner.setValue(new Integer((int) (h * 365)));
+      internalChange = false;
+      sSpinner.setValue(new Integer((int) (s * 100)));
+
+      revalidate();
+    }
+  }
+
+  /**
+   * This method listens for slider value changes.
+   */
+  class SliderChangeListener implements ChangeListener
+  {
+    /**
+     * This method is called when the slider value changes. It should change
+     * the color of the JColorChooser.
+     *
+     * @param e The ChangeEvent.
+     */
+    public void stateChanged(ChangeEvent e)
+    {
+      if (internalChange)
+       return;
+
+      Integer value = new Integer(slider.getValue());
+
+      switch (locked)
+        {
+       case HLOCKED:
+         hSpinner.setValue(value);
+         break;
+       case SLOCKED:
+         sSpinner.setValue(value);
+         break;
+       case BLOCKED:
+         bSpinner.setValue(value);
+         break;
+        }
+    }
+  }
+
+  /**
+   * This helper class determines the active JSpinner.
+   */
+  class RadioStateListener implements ChangeListener
+  {
+    /**
+     * This method is called when there is a new JRadioButton that was
+     * selected. As a result, it should activate the associated JSpinner.
+     *
+     * @param e The ChangeEvent.
+     */
+    public void stateChanged(ChangeEvent e)
+    {
+      JSpinner change;
+      if (e.getSource() == hRadio)
+        {
+         locked = HLOCKED;
+         change = hSpinner;
+        }
+      else if (e.getSource() == sRadio)
+        {
+         locked = SLOCKED;
+         change = sSpinner;
+        }
+      else
+        {
+         locked = BLOCKED;
+         change = bSpinner;
+        }
+
+      change.setEnabled(((AbstractButton) e.getSource()).isSelected());
+      updateSlider();
+      updateTrack();
+      updateImage();
+      repaint();
+    }
+  }
+
+  /**
+   * This class listens to the JSpinners for changes.
+   */
+  class ImageScrollListener implements ChangeListener
+  {
+    /**
+     * This method is called whenever one of the JSpinner values change. The
+     * JColorChooser should be updated with the new HSB values.
+     *
+     * @param e The ChangeEvent.
+     */
+    public void stateChanged(ChangeEvent e)
+    {
+      if (internalChange)
+       return;
+
+      float h = ((Number) hSpinner.getValue()).intValue() / 360f;
+      float s = ((Number) sSpinner.getValue()).intValue() / 100f;
+      float b = ((Number) bSpinner.getValue()).intValue() / 100f;
+
+      spinnerTrigger = true;
+      getColorSelectionModel().setSelectedColor(new Color(Color.HSBtoRGB(h, s,
+                                                                         b)));
+      spinnerTrigger = false;
+
+      if (! handlingMouse)
+        {
+         updateImage();
+         updateTrack();
+        }
+      repaint();
+    }
+  }
+
+  /**
+   * Creates a new DefaultHSBChooserPanel object.
+   */
+  DefaultHSBChooserPanel()
+  {
+    super();
+  }
+
+  /**
+   * This method returns the name displayed by the JColorChooser tab that
+   * holds this panel.
+   *
+   * @return The name displayed in the JColorChooser tab.
+   */
+  public String getDisplayName()
+  {
+    return "HSB";
+  }
+
+  /**
+   * This method updates the various components inside the HSBPanel (the
+   * JSpinners, the JSlider, and the gradient image point) with updated
+   * values when the JColorChooser color value changes.
+   */
+  public void updateChooser()
+  {
+    Color c = getColorSelectionModel().getSelectedColor();
+
+    float[] hsbVals = Color.RGBtoHSB(c.getRed(), c.getGreen(), c.getBlue(),
+                                     null);
+
+    internalChange = true;
+
+    // spinnerTrigger, internalChange, and handlingMouse are used because of the
+    // we don't want things like: change spinner -> update chooser -> change spinner
+    // That's because the value from before and after the update can differ
+    // slightly because of the conversion.
+    // FIXME: Think of better way to deal with this.
+    if (! spinnerTrigger)
+      {
+       hSpinner.setValue(new Integer((int) (hsbVals[0] * 360)));
+       sSpinner.setValue(new Integer((int) (hsbVals[1] * 100)));
+       bSpinner.setValue(new Integer((int) (hsbVals[2] * 100)));
+      }
+
+    switch (locked)
+      {
+      case HLOCKED:
+       if (slider != null)
+         slider.setValue(((Number) hSpinner.getValue()).intValue());
+       if (! handlingMouse)
+         {
+           gradientPoint.x = (int) ((1 - hsbVals[1]) * imgWidth);
+           gradientPoint.y = (int) ((1 - hsbVals[2]) * imgHeight);
+         }
+       break;
+      case SLOCKED:
+       if (slider != null)
+         slider.setValue(((Number) sSpinner.getValue()).intValue());
+       if (! handlingMouse)
+         {
+           gradientPoint.x = (int) (hsbVals[0] * imgWidth);
+           gradientPoint.y = (int) ((1 - hsbVals[2]) * imgHeight);
+         }
+       break;
+      case BLOCKED:
+       if (slider != null)
+         slider.setValue(((Number) bSpinner.getValue()).intValue());
+       if (! handlingMouse)
+         {
+           gradientPoint.x = (int) (hsbVals[0] * imgWidth);
+           gradientPoint.y = (int) ((1 - hsbVals[1]) * imgHeight);
+         }
+       break;
+      }
+    internalChange = false;
+
+    updateImage();
+    updateTrack();
+    updateTextFields();
+  }
+
+  /**
+   * This method builds the DefaultHSBChooserPanel.
+   */
+  protected void buildChooser()
+  {
+    setLayout(new BorderLayout());
+
+    add(buildRightPanel(), BorderLayout.EAST);
+
+    JPanel container = new JPanel();
+    container.setLayout(new BorderLayout());
+
+    gradientPanel = new JPanel()
+        {
+         public Dimension getPreferredSize()
+         {
+           return new Dimension(imgWidth, imgHeight);
+         }
+
+         public void paint(Graphics g)
+         {
+           if (gradientImage != null)
+             g.drawImage(gradientImage, 0, 0, this);
+
+           Color saved = g.getColor();
+           g.setColor(Color.WHITE);
+           g.drawOval(gradientPoint.x - 3, gradientPoint.y - 3, 6, 6);
+           g.setColor(saved);
+         }
+        };
+
+    MouseAdapter ml = new MainGradientMouseListener();
+    gradientPanel.addMouseListener(ml);
+    gradientPanel.addMouseMotionListener((MouseMotionListener) ml);
+
+    trackPanel = new JPanel()
+        {
+         public Dimension getPreferredSize()
+         {
+           return new Dimension(trackWidth, imgHeight);
+         }
+
+         public void paint(Graphics g)
+         {
+           if (trackImage != null)
+             g.drawImage(trackImage, 0, 0, this);
+         }
+        };
+
+    slider = new JSlider();
+    slider.setPaintTrack(false);
+    slider.setPaintTicks(false);
+
+    slider.setOrientation(SwingConstants.VERTICAL);
+
+    updateSlider();
+
+    container.add(gradientPanel, BorderLayout.WEST);
+    container.add(slider, BorderLayout.CENTER);
+    container.add(trackPanel, BorderLayout.EAST);
+
+    add(container, BorderLayout.WEST);
+    slider.addChangeListener(new SliderChangeListener());
+    repaint();
+  }
+
+  /**
+   * This method uninstalls the DefaultHSBPanel.
+   *
+   * @param chooser The JColorChooser to remove this panel from.
+   */
+  public void uninstallChooserPanel(JColorChooser chooser)
+  {
+    trackImage = null;
+    gradientImage = null;
+    gradientPanel = null;
+    slider = null;
+
+    hSpinner = null;
+    sSpinner = null;
+    bSpinner = null;
+
+    hRadio = null;
+    sRadio = null;
+    bRadio = null;
+
+    removeAll();
+    super.uninstallChooserPanel(chooser);
+  }
+
+  /**
+   * This helper method creates the right side panel (the panel with the
+   * Spinners and TextFields).
+   *
+   * @return The right side panel.
+   */
+  private Container buildRightPanel()
+  {
+    JPanel container = new JPanel();
+    container.setLayout(new GridLayout(6, 2));
+
+    hRadio = new JRadioButton("H");
+    sRadio = new JRadioButton("S");
+    bRadio = new JRadioButton("B");
+
+    ButtonGroup group = new ButtonGroup();
+    group.add(hRadio);
+    group.add(sRadio);
+    group.add(bRadio);
+
+    hSpinner = new JSpinner(new SpinnerNumberModel(0, 0, 359, 1));
+    sSpinner = new JSpinner(new SpinnerNumberModel(0, 0, 100, 1));
+    bSpinner = new JSpinner(new SpinnerNumberModel(100, 0, 100, 1));
+
+    hSpinner.setEnabled(false);
+    sSpinner.setEnabled(false);
+    bSpinner.setEnabled(false);
+
+    ChangeListener cl = new RadioStateListener();
+    ChangeListener scroll = new ImageScrollListener();
+
+    hRadio.addChangeListener(cl);
+    sRadio.addChangeListener(cl);
+    bRadio.addChangeListener(cl);
+
+    hSpinner.addChangeListener(scroll);
+    sSpinner.addChangeListener(scroll);
+    bSpinner.addChangeListener(scroll);
+
+    hRadio.setSelected(true);
+
+    container.add(hRadio);
+    container.add(hSpinner);
+
+    container.add(sRadio);
+    container.add(sSpinner);
+
+    container.add(bRadio);
+    container.add(bSpinner);
+
+    rFull = new JLabel("red full");
+    gFull = new JLabel("green full");
+    bFull = new JLabel("blue full");
+
+    container.add(R);
+    container.add(rFull);
+
+    container.add(G);
+    container.add(gFull);
+
+    container.add(B);
+    container.add(bFull);
+
+    return container;
+  }
+
+  /**
+   * This method returns the small display icon.
+   *
+   * @return The small display icon.
+   */
+  public Icon getSmallDisplayIcon()
+  {
+    return null;
+  }
+
+  /**
+   * This method returns the large display icon.
+   *
+   * @return The large display icon.
+   */
+  public Icon getLargeDisplayIcon()
+  {
+    return null;
+  }
+
+  /**
+   * This method paints the chooser panel.
+   *
+   * @param g The graphics object to paint with.
+   */
+  public void paint(Graphics g)
+  {
+    super.paint(g);
+  }
+
+  /**
+   * This method updates the gradient image with a new one taking the Hue
+   * value as the constant.
+   */
+  private void updateHLockImage()
+  {
+    int index = 0;
+    int[] pix = new int[imgWidth * imgHeight];
+    float hValue = ((Number) hSpinner.getValue()).intValue() / 360f;
+
+    for (int j = 0; j < imgHeight; j++)
+      for (int i = 0; i < imgWidth; i++)
+       pix[index++] = Color.HSBtoRGB(hValue, (imgWidth - i * 1f) / imgWidth,
+                                     (imgHeight - j * 1f) / imgHeight)
+                      | (255 << 24);
+
+    gradientImage = createImage(new MemoryImageSource(imgWidth, imgHeight,
+                                                      pix, 0, imgWidth));
+  }
+
+  /**
+   * This method updates the gradient image with a new one taking the
+   * Brightness value as the constant.
+   */
+  private void updateBLockImage()
+  {
+    int[] pix = new int[imgWidth * imgHeight];
+    float bValue = ((Number) bSpinner.getValue()).intValue() / 100f;
+
+    int index = 0;
+    for (int j = 0; j < imgHeight; j++)
+      for (int i = 0; i < imgWidth; i++)
+       pix[index++] = Color.HSBtoRGB(i * 1f / imgWidth,
+                                     (imgHeight - j * 1f) / imgHeight, bValue)
+                      | (255 << 24);
+
+    gradientImage = createImage(new MemoryImageSource(imgWidth, imgHeight,
+                                                      pix, 0, imgWidth));
+  }
+
+  /**
+   * This method updates the gradient image with a new one taking the
+   * Saturation value as the constant.
+   */
+  private void updateSLockImage()
+  {
+    int[] pix = new int[imgWidth * imgHeight];
+    float sValue = ((Number) sSpinner.getValue()).intValue() / 100f;
+
+    int index = 0;
+    for (int j = 0; j < imgHeight; j++)
+      for (int i = 0; i < imgWidth; i++)
+       pix[index++] = Color.HSBtoRGB(i * 1f / imgWidth, sValue,
+                                     (imgHeight - j * 1f) / imgHeight)
+                      | (255 << 24);
+    gradientImage = createImage(new MemoryImageSource(imgWidth, imgHeight,
+                                                      pix, 0, imgWidth));
+  }
+
+  /**
+   * This method calls the appropriate method to update the gradient image
+   * depending on which HSB value is constant.
+   */
+  private void updateImage()
+  {
+    switch (locked)
+      {
+      case HLOCKED:
+       updateHLockImage();
+       break;
+      case SLOCKED:
+       updateSLockImage();
+       break;
+      case BLOCKED:
+       updateBLockImage();
+       break;
+      }
+  }
+
+  /**
+   * This method updates the TextFields with the correct RGB values.
+   */
+  private void updateTextFields()
+  {
+    int c = getColorSelectionModel().getSelectedColor().getRGB();
+
+    rFull.setText("" + (c >> 16 & 0xff));
+    gFull.setText("" + (c >> 8 & 0xff));
+    bFull.setText("" + (c & 0xff));
+
+    repaint();
+  }
+
+  /**
+   * This method updates the slider in response to making a different HSB
+   * property the constant.
+   */
+  private void updateSlider()
+  {
+    if (slider == null)
+      return;
+
+    slider.setMinimum(0);
+    if (locked == HLOCKED)
+      {
+       slider.setMaximum(359);
+       ;
+       slider.setValue(((Number) hSpinner.getValue()).intValue());
+       slider.setInverted(true);
+      }
+    else
+      {
+       slider.setMaximum(100);
+       slider.setInverted(false);
+       if (sRadio.isSelected())
+         slider.setValue(((Number) sSpinner.getValue()).intValue());
+       else
+         slider.setValue(((Number) bSpinner.getValue()).intValue());
+      }
+    repaint();
+  }
+
+  /**
+   * This method updates the track gradient image depending on which HSB
+   * property is constant.
+   */
+  private void updateTrack()
+  {
+    switch (locked)
+      {
+      case HLOCKED:
+       updateHTrack();
+       break;
+      case SLOCKED:
+       updateSTrack();
+       break;
+      case BLOCKED:
+       updateBTrack();
+       break;
+      }
+  }
+
+  /**
+   * This method updates the track gradient image if the Hue value is allowed
+   * to change (according to the JRadioButtons).
+   */
+  private void updateHTrack()
+  {
+    int trackIndex = 0;
+    int[] trackPix = new int[trackWidth * imgHeight];
+
+    for (int j = 0; j < imgHeight; j++)
+      for (int i = 0; i < trackWidth; i++)
+       trackPix[trackIndex++] = Color.HSBtoRGB(j * 1f / imgHeight, 1f, 1f)
+                                | (255 << 24);
+
+    trackImage = createImage(new MemoryImageSource(trackWidth, imgHeight,
+                                                   trackPix, 0, trackWidth));
+  }
+
+  /**
+   * This method updates the track gradient image if the Saturation value is
+   * allowed to change (according to the JRadioButtons).
+   */
+  private void updateSTrack()
+  {
+    int[] trackPix = new int[trackWidth * imgHeight];
+
+    float hValue = ((Number) hSpinner.getValue()).intValue() / 360f;
+    float bValue = ((Number) bSpinner.getValue()).intValue() / 100f;
+
+    int trackIndex = 0;
+    for (int j = 0; j < imgHeight; j++)
+      for (int i = 0; i < trackWidth; i++)
+       trackPix[trackIndex++] = Color.HSBtoRGB(hValue,
+                                               (imgHeight - j * 1f) / imgHeight,
+                                               bValue) | (255 << 24);
+
+    trackImage = createImage(new MemoryImageSource(trackWidth, imgHeight,
+                                                   trackPix, 0, trackWidth));
+  }
+
+  /**
+   * This method updates the track gradient image if the Brightness value is
+   * allowed to change (according to the JRadioButtons).
+   */
+  private void updateBTrack()
+  {
+    int[] trackPix = new int[trackWidth * imgHeight];
+
+    float hValue = ((Number) hSpinner.getValue()).intValue() / 360f;
+    float sValue = ((Number) sSpinner.getValue()).intValue() / 100f;
+
+    int trackIndex = 0;
+    for (int j = 0; j < imgHeight; j++)
+      for (int i = 0; i < trackWidth; i++)
+       trackPix[trackIndex++] = Color.HSBtoRGB(hValue, sValue,
+                                               (imgHeight - j * 1f) / imgHeight)
+                                | (255 << 24);
+
+    trackImage = createImage(new MemoryImageSource(trackWidth, imgHeight,
+                                                   trackPix, 0, trackWidth));
+  }
+}
diff --git a/libjava/javax/swing/colorchooser/DefaultPreviewPanel.java b/libjava/javax/swing/colorchooser/DefaultPreviewPanel.java
new file mode 100644 (file)
index 0000000..93ecfc3
--- /dev/null
@@ -0,0 +1,317 @@
+/* DefaultPreviewPanel.java --
+   Copyright (C) 2004 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+package javax.swing.colorchooser;
+
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Dimension;
+import java.awt.FontMetrics;
+import java.awt.Graphics;
+import java.awt.Insets;
+import javax.swing.JColorChooser;
+import javax.swing.JPanel;
+import javax.swing.SwingUtilities;
+import javax.swing.border.Border;
+
+
+/**
+ * This is the default preview panel for the JColorChooser. The default
+ * preview panel is responsible for displaying the currently selected color
+ * of the JColorChooser.
+ */
+class DefaultPreviewPanel extends JPanel
+{
+  /**
+   * This is the border around the preview panel.
+   */
+  class PreviewBorder implements Border
+  {
+    /** This is the value of the top, bottom, top, and right inset. */
+    private static final int edge = 20;
+
+    /**
+     * This is the distance from the top left corner of the border to the
+     * text.
+     */
+    private static final int lead = 5;
+
+    /** This is the horizontal gap between the text and the border. */
+    private static final int gap = 3;
+
+    /**
+     * This method returns the border insets for the given Component.
+     *
+     * @param c The Component to retrieve insets for.
+     *
+     * @return The insets for the given Component.
+     */
+    public Insets getBorderInsets(Component c)
+    {
+      return new Insets(edge, edge, edge, edge);
+    }
+
+    /**
+     * This method returns whether the border is responsible for painting its
+     * own background.
+     *
+     * @return Whether the border is responsible for painting its own
+     *         background.
+     */
+    public boolean isBorderOpaque()
+    {
+      return true;
+    }
+
+    /**
+     * This method paints the border for the given component with the graphics
+     * object using the given properties.
+     *
+     * @param c The Component to paint the border for.
+     * @param g The Graphics object to paint with.
+     * @param x The x location to paint at.
+     * @param y The y location to paint at.
+     * @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)
+    {
+      Color saved = g.getColor();
+      FontMetrics fm = g.getFontMetrics();
+
+      g.setColor(Color.BLACK);
+      g.drawLine(x + edge / 2, y + edge / 2, x + edge / 2,
+                 y + height - edge / 2);
+      g.drawLine(x + edge / 2, y + height - edge / 2, x + width - edge / 2,
+                 y + height - edge / 2);
+      g.drawLine(x + width - edge / 2, y + edge / 2, x + width - edge / 2,
+                 y + height - edge / 2);
+      g.drawLine(x + edge / 2, y + edge / 2, x + edge / 2 + lead, y + edge / 2);
+
+      int strwidth = fm.stringWidth("Preview");
+
+      g.drawString("Preview", x + edge / 2 + lead + gap,
+                   y + edge / 2 + fm.getAscent() / 2);
+
+      g.drawLine(x + lead + edge / 2 + strwidth + gap * 2, y + edge / 2,
+                 x + width - edge / 2, y + edge / 2);
+
+      g.setColor(saved);
+    }
+  }
+
+  /** A standard large gap size. */
+  private static int largeGap = 6;
+
+  /** A standard small gap size. */
+  private static int smallGap = 2;
+
+  /** The size of each side of the square. */
+  private static int squareSize = 36;
+
+  /** This padding between the text and the edge of its box. */
+  private static int textPadding = 4;
+
+  /** The width of the right most rectangles. */
+  private static int rightSideRectWidth = 60;
+
+  /** The sample text. */
+  private static String sample = "Sample Text   Sample Text";
+
+  /**
+   * Creates a new DefaultPreviewPanel object.
+   */
+  DefaultPreviewPanel()
+  {
+    super();
+    setBorder(new PreviewBorder());
+  }
+
+  /**
+   * This method paints the default preview panel with the given Graphics
+   * object.
+   *
+   * @param g The Graphics object.
+   */
+  public void paint(Graphics g)
+  {
+    super.paint(g);
+    Color currentColor = null;
+    JColorChooser chooser = (JColorChooser) SwingUtilities.getAncestorOfClass(JColorChooser.class,
+                                                                              this);
+    if (chooser != null)
+      currentColor = chooser.getColor();
+
+    Color saved = g.getColor();
+    Insets insets = getInsets();
+
+    int down = insets.top + squareSize + largeGap;
+    int currX = insets.left;
+
+    paintSquare(g, currX, insets.top, Color.WHITE, currentColor, Color.WHITE,
+                -1, -1, -1);
+    paintSquare(g, currX, down, currentColor, null, null, -1, -1, -1);
+
+    currX += squareSize + largeGap;
+
+    paintSquare(g, currX, insets.top, Color.BLACK, currentColor, Color.WHITE,
+                -1, -1, -1);
+    paintSquare(g, currX, down, Color.WHITE, currentColor, null, -1, -1, -1);
+
+    currX += squareSize + largeGap;
+
+    paintSquare(g, currX, insets.top, Color.WHITE, currentColor, Color.BLACK,
+                -1, -1, -1);
+    paintSquare(g, currX, down, Color.BLACK, currentColor, null, -1, -1, -1);
+
+    FontMetrics fm = g.getFontMetrics();
+    int strWidth = fm.stringWidth(sample);
+    int strHeight = fm.getHeight();
+
+    currX += squareSize + largeGap;
+
+    int boxWidth = 2 * textPadding + strWidth;
+    int boxHeight = 2 * textPadding + strHeight;
+
+    int first = insets.top + textPadding;
+    int second = insets.top + boxHeight + smallGap;
+    int third = insets.top + 2 * (boxHeight + smallGap);
+
+    g.setColor(Color.WHITE);
+    g.fillRect(currX, third, boxWidth, boxHeight);
+
+    g.setColor(currentColor);
+    g.drawString(sample, currX + textPadding,
+                 first + textPadding + fm.getAscent());
+
+    g.fillRect(currX, second, boxWidth, boxHeight);
+
+    g.drawString(sample, currX + textPadding,
+                 third + textPadding + fm.getAscent());
+
+    g.setColor(Color.BLACK);
+    g.drawString(sample, currX + textPadding,
+                 second + textPadding + fm.getAscent());
+
+    currX += boxWidth + largeGap;
+
+    g.setColor(Color.WHITE);
+    g.fillRect(currX, insets.top, rightSideRectWidth, squareSize
+               + largeGap / 2);
+
+    g.setColor(currentColor);
+    g.fillRect(currX, insets.top + squareSize + largeGap / 2,
+               rightSideRectWidth, squareSize + largeGap / 2);
+
+    g.setColor(saved);
+  }
+
+  /**
+   * This method creates and paints a square. The square has two smaller
+   * squares inside of it. Each of the three squares has their sizes
+   * determined by the size arguments. If the size is not given (by passing
+   * in -1), then the size is determined automatically.
+   *
+   * @param g The Graphics object to paint with.
+   * @param x The x location to paint at.
+   * @param y The y location to paint at.
+   * @param first The color of the first square.
+   * @param second The color of the second square.
+   * @param third The color of the third square.
+   * @param firstSize The size of the first square.
+   * @param secondSize The size of the second square.
+   * @param thirdSize The size of the third square.
+   */
+  private void paintSquare(Graphics g, int x, int y, Color first,
+                           Color second, Color third, int firstSize,
+                           int secondSize, int thirdSize)
+  {
+    Color saved = g.getColor();
+    if (firstSize == -1)
+      firstSize = squareSize;
+    if (secondSize == -1)
+      secondSize = squareSize * 2 / 3;
+    if (thirdSize == -1)
+      thirdSize = squareSize / 3;
+    int secondOffset = (firstSize - secondSize) / 2;
+    int thirdOffset = (firstSize - thirdSize) / 2;
+
+    if (first == null)
+      return;
+    g.setColor(first);
+    g.fillRect(x, y, firstSize, firstSize);
+    if (second == null)
+      return;
+    g.setColor(second);
+    g.fillRect(x + secondOffset, y + secondOffset, secondSize, secondSize);
+    if (third == null)
+      return;
+    g.setColor(third);
+    g.fillRect(x + thirdOffset, y + thirdOffset, thirdSize, thirdSize);
+
+    g.setColor(saved);
+  }
+
+  /**
+   * This method returns the preferred size of the default preview panel.
+   *
+   * @return The preferred size of the default preview panel.
+   */
+  public Dimension getPreferredSize()
+  {
+    Graphics g = getGraphics();
+    FontMetrics fm = g.getFontMetrics();
+    g.dispose();
+
+    int strWidth = fm.stringWidth(sample);
+    int strHeight = fm.getHeight();
+
+    int h1 = (strHeight + 2 * textPadding) * 3 + 2 * smallGap;
+    int h2 = 2 * squareSize + largeGap;
+
+    int height = Math.max(h1, h2);
+
+    int width = 3 * (squareSize + largeGap) + strWidth + 2 * textPadding
+                + largeGap + rightSideRectWidth;
+
+    Insets insets = getInsets();
+
+    return new Dimension(width + insets.right + insets.left,
+                         height + insets.top + insets.bottom);
+  }
+}
diff --git a/libjava/javax/swing/colorchooser/DefaultRGBChooserPanel.java b/libjava/javax/swing/colorchooser/DefaultRGBChooserPanel.java
new file mode 100644 (file)
index 0000000..f6c22e8
--- /dev/null
@@ -0,0 +1,377 @@
+/* DefaultRGHChooserPanel.java --
+   Copyright (C) 2004 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+package javax.swing.colorchooser;
+
+import java.awt.BorderLayout;
+import java.awt.Color;
+import java.awt.FlowLayout;
+import java.awt.Graphics;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import javax.swing.Icon;
+import javax.swing.JColorChooser;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JSlider;
+import javax.swing.JSpinner;
+import javax.swing.SpinnerNumberModel;
+import javax.swing.SwingConstants;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+
+
+/**
+ * This is the default RGB panel for the JColorChooser. The color is selected
+ * using three sliders that represent the RGB values.
+ */
+public class DefaultRGBChooserPanel extends AbstractColorChooserPanel
+{
+  /**
+   * This class handles the slider value changes for all three sliders.
+   */
+  class SliderHandler implements ChangeListener
+  {
+    /**
+     * This method is called whenever any of the slider values change.
+     *
+     * @param e The ChangeEvent.
+     */
+    public void stateChanged(ChangeEvent e)
+    {
+      if (internalChange)
+       return;
+      int color = R.getValue() << 16 | G.getValue() << 8 | B.getValue();
+
+      getColorSelectionModel().setSelectedColor(new Color(color));
+    }
+  }
+
+  /**
+   * This class handles the Spinner values changing.
+   */
+  class SpinnerHandler implements ChangeListener
+  {
+    /**
+     * This method is called whenever any of the JSpinners change values.
+     *
+     * @param e The ChangeEvent.
+     */
+    public void stateChanged(ChangeEvent e)
+    {
+      if (internalChange)
+       return;
+      int red = ((Number) RSpinner.getValue()).intValue();
+      int green = ((Number) GSpinner.getValue()).intValue();
+      int blue = ((Number) BSpinner.getValue()).intValue();
+
+      int color = red << 16 | green << 8 | blue;
+
+      getColorSelectionModel().setSelectedColor(new Color(color));
+    }
+  }
+
+  /**
+   * Whether the color change was initiated from the slider or spinner rather
+   * than externally.
+   */
+  private transient boolean internalChange = false;
+
+  /** The ChangeListener for the sliders. */
+  private transient ChangeListener colorChanger;
+
+  /** The ChangeListener for the spinners. */
+  private transient ChangeListener spinnerHandler;
+
+  /** The slider that handles the red values. */
+  private transient JSlider R;
+
+  /** The slider that handles the green values. */
+  private transient JSlider G;
+
+  /** The slider that handles the blue values. */
+  private transient JSlider B;
+
+  /** The label for the red slider. */
+  private transient JLabel RLabel;
+
+  /** The label for the green slider. */
+  private transient JLabel GLabel;
+
+  /** The label for the blue slider. */
+  private transient JLabel BLabel;
+
+  /** The spinner that handles the red values. */
+  private transient JSpinner RSpinner;
+
+  /** The spinner that handles the green values. */
+  private transient JSpinner GSpinner;
+
+  /** The spinner that handles the blue values. */
+  private transient JSpinner BSpinner;
+
+  /**
+   * Creates a new DefaultRGBChooserPanel object.
+   */
+  public DefaultRGBChooserPanel()
+  {
+    super();
+  }
+
+  /**
+   * This method returns the name displayed in the JTabbedPane.
+   *
+   * @return The name displayed in the JTabbedPane.
+   */
+  public String getDisplayName()
+  {
+    return "RGB";
+  }
+
+  /**
+   * This method updates the chooser panel with the new color chosen in the
+   * JColorChooser.
+   */
+  public void updateChooser()
+  {
+    Color c = getColorFromModel();
+    int rgb = c.getRGB();
+
+    int red = rgb >> 16 & 0xff;
+    int green = rgb >> 8 & 0xff;
+    int blue = rgb & 0xff;
+
+    internalChange = true;
+
+    if (R != null)
+      R.setValue(red);
+    if (RSpinner != null)
+      RSpinner.setValue(new Integer(red));
+    if (G != null)
+      G.setValue(green);
+    if (GSpinner != null)
+      GSpinner.setValue(new Integer(green));
+    if (B != null)
+      B.setValue(blue);
+    if (BSpinner != null)
+      BSpinner.setValue(new Integer(blue));
+
+    internalChange = false;
+
+    revalidate();
+    repaint();
+  }
+
+  /**
+   * This method builds the chooser panel.
+   */
+  protected void buildChooser()
+  {
+    setLayout(new GridBagLayout());
+
+    RLabel = new JLabel("Red");
+    RLabel.setDisplayedMnemonic('d');
+    GLabel = new JLabel("Green");
+    GLabel.setDisplayedMnemonic('n');
+    BLabel = new JLabel("Blue");
+    BLabel.setDisplayedMnemonic('B');
+
+    R = new JSlider(SwingConstants.HORIZONTAL, 0, 255, 255);
+    G = new JSlider(SwingConstants.HORIZONTAL, 0, 255, 255);
+    B = new JSlider(SwingConstants.HORIZONTAL, 0, 255, 255);
+
+    R.setPaintTicks(true);
+    R.setSnapToTicks(false);
+    G.setPaintTicks(true);
+    G.setSnapToTicks(false);
+    B.setPaintTicks(true);
+    B.setSnapToTicks(false);
+
+    R.setLabelTable(R.createStandardLabels(85));
+    R.setPaintLabels(true);
+    G.setLabelTable(G.createStandardLabels(85));
+    G.setPaintLabels(true);
+    B.setLabelTable(B.createStandardLabels(85));
+    B.setPaintLabels(true);
+
+    R.setMajorTickSpacing(85);
+    G.setMajorTickSpacing(85);
+    B.setMajorTickSpacing(85);
+
+    R.setMinorTickSpacing(17);
+    G.setMinorTickSpacing(17);
+    B.setMinorTickSpacing(17);
+
+    RSpinner = new JSpinner(new SpinnerNumberModel(R.getValue(),
+                                                   R.getMinimum(),
+                                                   R.getMaximum(), 1));
+    GSpinner = new JSpinner(new SpinnerNumberModel(G.getValue(),
+                                                   G.getMinimum(),
+                                                   G.getMaximum(), 1));
+    BSpinner = new JSpinner(new SpinnerNumberModel(B.getValue(),
+                                                   B.getMinimum(),
+                                                   B.getMaximum(), 1));
+
+    RLabel.setLabelFor(R);
+    GLabel.setLabelFor(G);
+    BLabel.setLabelFor(B);
+
+    GridBagConstraints bag = new GridBagConstraints();
+    bag.fill = GridBagConstraints.VERTICAL;
+
+    bag.gridx = 0;
+    bag.gridy = 0;
+    add(RLabel, bag);
+
+    bag.gridx = 1;
+    add(R, bag);
+
+    bag.gridx = 2;
+    add(RSpinner, bag);
+
+    bag.gridx = 0;
+    bag.gridy = 1;
+    add(GLabel, bag);
+
+    bag.gridx = 1;
+    add(G, bag);
+
+    bag.gridx = 2;
+    add(GSpinner, bag);
+
+    bag.gridx = 0;
+    bag.gridy = 2;
+    add(BLabel, bag);
+
+    bag.gridx = 1;
+    add(B, bag);
+
+    bag.gridx = 2;
+    add(BSpinner, bag);
+
+    installListeners();
+  }
+
+  /**
+   * This method uninstalls the chooser panel from the JColorChooser.
+   *
+   * @param chooser The JColorChooser to remove this chooser panel from.
+   */
+  public void uninstallChooserPanel(JColorChooser chooser)
+  {
+    uninstallListeners();
+    removeAll();
+
+    R = null;
+    G = null;
+    B = null;
+
+    RSpinner = null;
+    GSpinner = null;
+    BSpinner = null;
+
+    super.uninstallChooserPanel(chooser);
+  }
+
+  /**
+   * This method uninstalls any listeners that were added by the chooser
+   * panel.
+   */
+  private void uninstallListeners()
+  {
+    R.removeChangeListener(colorChanger);
+    G.removeChangeListener(colorChanger);
+    B.removeChangeListener(colorChanger);
+
+    colorChanger = null;
+
+    RSpinner.removeChangeListener(spinnerHandler);
+    GSpinner.removeChangeListener(spinnerHandler);
+    BSpinner.removeChangeListener(spinnerHandler);
+
+    spinnerHandler = null;
+  }
+
+  /**
+   * This method installs any listeners that the chooser panel needs to
+   * operate.
+   */
+  private void installListeners()
+  {
+    colorChanger = new SliderHandler();
+
+    R.addChangeListener(colorChanger);
+    G.addChangeListener(colorChanger);
+    B.addChangeListener(colorChanger);
+
+    spinnerHandler = new SpinnerHandler();
+
+    RSpinner.addChangeListener(spinnerHandler);
+    GSpinner.addChangeListener(spinnerHandler);
+    BSpinner.addChangeListener(spinnerHandler);
+  }
+
+  /**
+   * This method returns the small display icon.
+   *
+   * @return The small display icon.
+   */
+  public Icon getSmallDisplayIcon()
+  {
+    return null;
+  }
+
+  /**
+   * This method returns the large display icon.
+   *
+   * @return The large display icon.
+   */
+  public Icon getLargeDisplayIcon()
+  {
+    return null;
+  }
+
+  /**
+   * This method paints the default RGB chooser panel.
+   *
+   * @param g The Graphics object to paint with.
+   */
+  public void paint(Graphics g)
+  {
+    super.paint(g);
+  }
+}
diff --git a/libjava/javax/swing/colorchooser/DefaultSwatchChooserPanel.java b/libjava/javax/swing/colorchooser/DefaultSwatchChooserPanel.java
new file mode 100644 (file)
index 0000000..1413a5b
--- /dev/null
@@ -0,0 +1,891 @@
+/* DefaultSwatchChooserPanel.java --
+   Copyright (C) 2004 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+package javax.swing.colorchooser;
+
+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.LayoutManager;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseListener;
+import javax.swing.Icon;
+import javax.swing.JColorChooser;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+
+
+/**
+ * This class is the DefaultSwatchChooserPanel. This chooser panel displays a
+ * set of colors that can be picked. Recently picked items will go into a
+ * side panel so the user can see the history of the chosen colors.
+ */
+class DefaultSwatchChooserPanel extends AbstractColorChooserPanel
+{
+  /** The main panel that holds the set of choosable colors. */
+  MainSwatchPanel mainPalette;
+
+  /** A panel that holds the recent colors. */
+  RecentSwatchPanel recentPalette;
+
+  /** The mouse handlers for the panels. */
+  MouseListener mouseHandler;
+
+  /**
+   * This the base class for all swatch panels. Swatch panels are panels that
+   * hold a set of blocks where colors are displayed.
+   */
+  abstract static class SwatchPanel extends JPanel
+  {
+    /** The width of each block. */
+    protected int cellWidth = 10;
+
+    /** The height of each block. */
+    protected int cellHeight = 10;
+
+    /** The gap between blocks. */
+    protected int gap = 1;
+
+    /** The number of rows in the swatch panel. */
+    protected int numRows;
+
+    /** The number of columns in the swatch panel. */
+    protected int numCols;
+
+    /**
+     * Creates a new SwatchPanel object.
+     */
+    SwatchPanel()
+    {
+      super();
+      setBackground(Color.WHITE);
+    }
+
+    /**
+     * This method returns the preferred size of the swatch panel based on the
+     * number of rows and columns and the size of each cell.
+     *
+     * @return The preferred size of the swatch panel.
+     */
+    public Dimension getPreferredSize()
+    {
+      int height = numRows * cellHeight + (numRows - 1) * gap;
+      int width = numCols * cellWidth + (numCols - 1) * gap;
+      Insets insets = getInsets();
+
+      return new Dimension(width + insets.left + insets.right,
+                           height + insets.top + insets.bottom);
+    }
+
+    /**
+     * This method returns the color for the given position.
+     *
+     * @param x The x coordinate of the position.
+     * @param y The y coordinate of the position.
+     *
+     * @return The color at the given position.
+     */
+    public abstract Color getColorForPosition(int x, int y);
+
+    /**
+     * This method initializes the colors for the swatch panel.
+     */
+    protected abstract void initializeColors();
+  }
+
+  /**
+   * This is the main swatch panel. This panel sits in the middle and allows a
+   * set of colors to be picked which will move to the recent swatch panel.
+   */
+  static class MainSwatchPanel extends SwatchPanel
+  {
+    /** The color describing (204, 255, 255) */
+    public static final Color C204255255 = new Color(204, 204, 255);
+
+    /** The color describing (255, 204, 204) */
+    public static final Color C255204204 = new Color(255, 204, 204);
+
+    /** The color describing (204, 255, 204) */
+    public static final Color C204255204 = new Color(204, 255, 204);
+
+    /** The color describing (204, 204, 204) */
+    public static final Color C204204204 = new Color(204, 204, 204);
+
+    /** The color (153, 153, 255). */
+    public static final Color C153153255 = new Color(153, 153, 255);
+
+    /** The color (51, 51, 255). */
+    public static final Color C051051255 = new Color(51, 51, 255);
+
+    /** The color (153, 0, 153). */
+    public static final Color C153000153 = new Color(153, 0, 153);
+
+    /** The color (0, 51, 51). */
+    public static final Color C000051051 = new Color(0, 51, 51);
+
+    /** The color (51, 0, 51). */
+    public static final Color C051000051 = new Color(51, 0, 51);
+
+    /** The color (51, 51, 0). */
+    public static final Color C051051000 = new Color(51, 51, 0);
+
+    /** The color (102, 102, 0). */
+    public static final Color C102102000 = new Color(102, 102, 0);
+
+    /** The color (153, 255, 153). */
+    public static final Color C153255153 = new Color(153, 255, 153);
+
+    /** The color (102, 255, 102). */
+    public static final Color C102255102 = new Color(102, 255, 102);
+
+    /** The color (0, 102, 102). */
+    public static final Color C000102102 = new Color(0, 102, 102);
+
+    /** The color (102, 0, 102). */
+    public static final Color C102000102 = new Color(102, 0, 102);
+
+    /** The color (0, 153, 153). */
+    public static final Color C000153153 = new Color(0, 153, 153);
+
+    /** The color (153, 153, 0). */
+    public static final Color C153153000 = new Color(153, 153, 0);
+
+    /** The color (204, 204, 0). */
+    public static final Color C204204000 = new Color(204, 204, 0);
+
+    /** The color (204, 0, 204). */
+    public static final Color C204000204 = new Color(204, 0, 204);
+
+    /** The color (0, 204, 204). */
+    public static final Color C000204204 = new Color(0, 204, 204);
+
+    /** The color (51, 255, 51). */
+    public static final Color C051255051 = new Color(51, 255, 51);
+
+    /** The color (255, 51, 51). */
+    public static final Color C255051051 = new Color(255, 51, 51);
+
+    /** The color (255, 102, 102). */
+    public static final Color C255102102 = new Color(255, 102, 102);
+
+    /** The color (102, 102, 255). */
+    public static final Color C102102255 = new Color(102, 102, 255);
+
+    /** The color (255, 153, 153). */
+    public static final Color C255153153 = new Color(255, 153, 153);
+    static Color[] colors = 
+                            {
+                              // Row 1
+    Color.WHITE, new Color(204, 255, 255), C204255255, C204255255, C204255255,
+                              C204255255, C204255255, C204255255, C204255255,
+                              C204255255, C204255255, new Color(255, 204, 255),
+                              C255204204, C255204204, C255204204, C255204204,
+                              C255204204, C255204204, C255204204, C255204204,
+                              C255204204, new Color(255, 255, 204), C204255204,
+                              C204255204, C204255204, C204255204, C204255204,
+                              C204255204, C204255204, C204255204, C204255204,
+                              
+    // Row 2
+    C204204204, new Color(153, 255, 255), new Color(153, 204, 255), C153153255,
+                              C153153255, C153153255, C153153255, C153153255,
+                              C153153255, C153153255, new Color(204, 153, 255),
+                              new Color(255, 153, 255),
+                              new Color(255, 153, 204), C255153153, C255153153,
+                              C255153153, C255153153, C255153153, C255153153,
+                              C255153153, new Color(255, 204, 153),
+                              new Color(255, 255, 153),
+                              new Color(204, 255, 153), C153255153, C153255153,
+                              C153255153, C153255153, C153255153, C153255153,
+                              C153255153, new Color(153, 255, 204),
+                              
+    // Row 3
+    C204204204, new Color(102, 255, 255), new Color(102, 204, 255),
+                              new Color(102, 153, 255), C102102255, C102102255,
+                              C102102255, C102102255, C102102255,
+                              new Color(153, 102, 255),
+                              new Color(204, 102, 255),
+                              new Color(255, 102, 255),
+                              new Color(255, 102, 204),
+                              new Color(255, 102, 153), C255102102, C255102102,
+                              C255102102, C255102102, C255102102,
+                              new Color(255, 153, 102),
+                              new Color(255, 204, 102),
+                              new Color(255, 255, 102),
+                              new Color(204, 255, 102),
+                              new Color(153, 255, 102), C102255102, C102255102,
+                              C102255102, C102255102, C102255102,
+                              new Color(102, 255, 153),
+                              new Color(102, 255, 204),
+                              
+    // Row 4
+    new Color(153, 153, 153), new Color(51, 255, 255), new Color(51, 204, 255),
+                              new Color(51, 153, 255), new Color(51, 102, 255),
+                              C051051255, C051051255, C051051255,
+                              new Color(102, 51, 255), new Color(153, 51, 255),
+                              new Color(204, 51, 255), new Color(255, 51, 255),
+                              new Color(255, 51, 204), new Color(255, 51, 153),
+                              new Color(255, 51, 102), C255051051, C255051051,
+                              C255051051, new Color(255, 102, 51),
+                              new Color(255, 153, 51), new Color(255, 204, 51),
+                              new Color(255, 255, 51), new Color(204, 255, 51),
+                              new Color(153, 255, 51), new Color(102, 255, 51),
+                              C051255051, C051255051, C051255051,
+                              new Color(51, 255, 102), new Color(51, 255, 153),
+                              new Color(51, 255, 204),
+                              
+    // Row 5
+    new Color(153, 153, 153), new Color(0, 255, 255), new Color(0, 204, 255),
+                              new Color(0, 153, 255), new Color(0, 102, 255),
+                              new Color(0, 51, 255), new Color(0, 0, 255),
+                              new Color(51, 0, 255), new Color(102, 0, 255),
+                              new Color(153, 0, 255), new Color(204, 0, 255),
+                              new Color(255, 0, 255), new Color(255, 0, 204),
+                              new Color(255, 0, 153), new Color(255, 0, 102),
+                              new Color(255, 0, 51), new Color(255, 0, 0),
+                              new Color(255, 51, 0), new Color(255, 102, 0),
+                              new Color(255, 153, 0), new Color(255, 204, 0),
+                              new Color(255, 255, 0), new Color(204, 255, 0),
+                              new Color(153, 255, 0), new Color(102, 255, 0),
+                              new Color(51, 255, 0), new Color(0, 255, 0),
+                              new Color(0, 255, 51), new Color(0, 255, 102),
+                              new Color(0, 255, 153), new Color(0, 255, 204),
+                              
+    // Row 6
+    new Color(102, 102, 102), C000204204, C000204204, new Color(0, 153, 204),
+                              new Color(0, 102, 204), new Color(0, 51, 204),
+                              new Color(0, 0, 204), new Color(51, 0, 204),
+                              new Color(102, 0, 204), new Color(153, 0, 204),
+                              C204000204, C204000204, C204000204,
+                              new Color(204, 0, 153), new Color(204, 0, 102),
+                              new Color(204, 0, 51), new Color(204, 0, 0),
+                              new Color(204, 51, 0), new Color(204, 102, 0),
+                              new Color(204, 153, 0), C204204000, C204204000,
+                              C204204000, new Color(153, 204, 0),
+                              new Color(102, 204, 0), new Color(51, 204, 0),
+                              new Color(0, 204, 0), new Color(0, 204, 51),
+                              new Color(0, 204, 102), new Color(0, 204, 153),
+                              new Color(0, 204, 204),
+                              
+    // Row 7
+    new Color(102, 102, 102), C000153153, C000153153, C000153153,
+                              new Color(0, 102, 153), new Color(0, 51, 153),
+                              new Color(0, 0, 153), new Color(51, 0, 153),
+                              new Color(102, 0, 153), C153000153, C153000153,
+                              C153000153, C153000153, C153000153,
+                              new Color(153, 0, 102), new Color(153, 0, 51),
+                              new Color(153, 0, 0), new Color(153, 51, 0),
+                              new Color(153, 102, 0), C153153000, C153153000,
+                              C153153000, C153153000, C153153000,
+                              new Color(102, 153, 0), new Color(51, 153, 0),
+                              new Color(0, 153, 0), new Color(0, 153, 51),
+                              new Color(0, 153, 102), C000153153, C000153153,
+                              
+    // Row 8
+    new Color(51, 51, 51), C000102102, C000102102, C000102102, C000102102,
+                              new Color(0, 51, 102), new Color(0, 0, 102),
+                              new Color(51, 0, 102), C102000102, C102000102,
+                              C102000102, C102000102, C102000102, C102000102,
+                              C102000102, new Color(102, 0, 51),
+                              new Color(102, 0, 0), new Color(102, 51, 0),
+                              C102102000, C102102000, C102102000, C102102000,
+                              C102102000, C102102000, C102102000,
+                              new Color(51, 102, 0), new Color(0, 102, 0),
+                              new Color(0, 102, 51), C000102102, C000102102,
+                              C000102102,
+                              
+    // Row 9.
+    Color.BLACK, C000051051, C000051051, C000051051, C000051051, C000051051,
+                              new Color(0, 0, 51), C051000051, C051000051,
+                              C051000051, C051000051, C051000051, C051000051,
+                              C051000051, C051000051, C051000051,
+                              new Color(51, 0, 0), C051051000, C051051000,
+                              C051051000, C051051000, C051051000, C051051000,
+                              C051051000, C051051000, new Color(0, 51, 0),
+                              C000051051, C000051051, C000051051, C000051051,
+                              new Color(51, 51, 51)
+                            };
+
+    /**
+     * Creates a new MainSwatchPanel object.
+     */
+    MainSwatchPanel()
+    {
+      super();
+      numCols = 31;
+      numRows = 9;
+      initializeColors();
+      revalidate();
+    }
+
+    /**
+     * This method returns the color for the given position.
+     *
+     * @param x The x location for the position.
+     * @param y The y location for the position.
+     *
+     * @return The color for the given position.
+     */
+    public Color getColorForPosition(int x, int y)
+    {
+      if (x % (cellWidth + gap) > cellWidth
+          || y % (cellHeight + gap) > cellHeight)
+       // position is located in gap.
+       return null;
+
+      int row = y / (cellHeight + gap);
+      int col = x / (cellWidth + gap);
+      return colors[row * numCols + col];
+    }
+
+    /**
+     * This method initializes the colors for the main swatch panel.
+     */
+    protected void initializeColors()
+    {
+      // Unnecessary
+    }
+
+    /**
+     * This method paints the main graphics panel with the given Graphics
+     * object.
+     *
+     * @param graphics The Graphics object to paint with.
+     */
+    public void paint(Graphics graphics)
+    {
+      int index = 0;
+      Insets insets = getInsets();
+      int currX = insets.left;
+      int currY = insets.top;
+      Color saved = graphics.getColor();
+
+      for (int i = 0; i < numRows; i++)
+        {
+         for (int j = 0; j < numCols; j++)
+           {
+             graphics.setColor(colors[index++]);
+             graphics.fill3DRect(currX, currY, cellWidth, cellHeight, true);
+             currX += gap + cellWidth;
+           }
+         currX = insets.left;
+         currY += gap + cellHeight;
+        }
+      graphics.setColor(saved);
+    }
+
+    /**
+     * This method returns the tooltip text for the given MouseEvent.
+     *
+     * @param e The MouseEvent to find tooltip text for.
+     *
+     * @return The tooltip text.
+     */
+    public String getToolTipText(MouseEvent e)
+    {
+      Color c = getColorForPosition(e.getX(), e.getY());
+      if (c == null)
+       return null;
+      return (c.getRed() + "," + c.getGreen() + "," + c.getBlue());
+    }
+  }
+
+  /**
+   * This class is the recent swatch panel. It holds recently selected colors.
+   */
+  public static class RecentSwatchPanel extends SwatchPanel
+  {
+    /** The array for storing recently stored colors. */
+    Color[] colors;
+
+    /** The default color. */
+    public static final Color defaultColor = Color.GRAY;
+
+    /** The index of the array that is the start. */
+    int start = 0;
+
+    /**
+     * Creates a new RecentSwatchPanel object.
+     */
+    RecentSwatchPanel()
+    {
+      super();
+      numCols = 5;
+      numRows = 7;
+      initializeColors();
+      revalidate();
+    }
+
+    /**
+     * This method returns the color for the given position.
+     *
+     * @param x The x coordinate of the position.
+     * @param y The y coordinate of the position.
+     *
+     * @return The color for the given position.
+     */
+    public Color getColorForPosition(int x, int y)
+    {
+      if (x % (cellWidth + gap) > cellWidth
+          || y % (cellHeight + gap) > cellHeight)
+       // position is located in gap.
+       return null;
+
+      int row = y / (cellHeight + gap);
+      int col = x / (cellWidth + gap);
+
+      return colors[getIndexForCell(row, col)];
+    }
+
+    /**
+     * This method initializes the colors for the recent swatch panel.
+     */
+    protected void initializeColors()
+    {
+      colors = new Color[numRows * numCols];
+      for (int i = 0; i < colors.length; i++)
+       colors[i] = defaultColor;
+    }
+
+    /**
+     * This method returns the array index for the given row and column.
+     *
+     * @param row The row.
+     * @param col The column.
+     *
+     * @return The array index for the given row and column.
+     */
+    private int getIndexForCell(int row, int col)
+    {
+      return ((row * numCols) + col + start) % (numRows * numCols);
+    }
+
+    /**
+     * This method adds the given color to the beginning of the swatch panel.
+     *
+     * @param c The color to add.
+     */
+    private void addColorToQueue(Color c)
+    {
+      if (--start == -1)
+       start = numRows * numCols - 1;
+
+      colors[start] = c;
+    }
+
+    /**
+     * This method paints the panel with the given Graphics object.
+     *
+     * @param g The Graphics object to paint with.
+     */
+    public void paint(Graphics g)
+    {
+      Color saved = g.getColor();
+      Insets insets = getInsets();
+      int currX = insets.left;
+      int currY = insets.top;
+
+      for (int i = 0; i < numRows; i++)
+        {
+         for (int j = 0; j < numCols; j++)
+           {
+             g.setColor(colors[getIndexForCell(i, j)]);
+             g.fill3DRect(currX, currY, cellWidth, cellHeight, true);
+             currX += cellWidth + gap;
+           }
+         currX = insets.left;
+         currY += cellWidth + gap;
+        }
+    }
+
+    /**
+     * This method returns the tooltip text for the given MouseEvent.
+     *
+     * @param e The MouseEvent.
+     *
+     * @return The tooltip text.
+     */
+    public String getToolTipText(MouseEvent e)
+    {
+      Color c = getColorForPosition(e.getX(), e.getY());
+      if (c == null)
+       return null;
+      return c.getRed() + "," + c.getGreen() + "," + c.getBlue();
+    }
+  }
+
+  /**
+   * This class handles mouse events for the two swatch panels.
+   */
+  class MouseHandler extends MouseAdapter
+  {
+    /**
+     * This method is called whenever the mouse is pressed.
+     *
+     * @param e The MouseEvent.
+     */
+    public void mousePressed(MouseEvent e)
+    {
+      SwatchPanel panel = (SwatchPanel) e.getSource();
+      Color c = panel.getColorForPosition(e.getX(), e.getY());
+      recentPalette.addColorToQueue(c);
+      DefaultSwatchChooserPanel.this.getColorSelectionModel().setSelectedColor(c);
+      DefaultSwatchChooserPanel.this.repaint();
+    }
+  }
+
+  /**
+   * This is the layout manager for the main panel.
+   */
+  static class MainPanelLayout implements LayoutManager
+  {
+    /**
+     * This method is called when a new component is added to the container.
+     *
+     * @param name The name of the component.
+     * @param comp The added component.
+     */
+    public void addLayoutComponent(String name, Component comp)
+    {
+    }
+
+    /**
+     * This method is called to set the size and position of the child
+     * components for the given container.
+     *
+     * @param parent The container to lay out.
+     */
+    public void layoutContainer(Container parent)
+    {
+      Component[] comps = parent.getComponents();
+      Insets insets = parent.getInsets();
+      Dimension[] pref = new Dimension[comps.length];
+
+      int xpos = 0;
+      int ypos = 0;
+      int maxHeight = 0;
+      int totalWidth = 0;
+
+      for (int i = 0; i < comps.length; i++)
+        {
+         pref[i] = comps[i].getPreferredSize();
+         if (pref[i] == null)
+           return;
+         maxHeight = Math.max(maxHeight, pref[i].height);
+         totalWidth += pref[i].width;
+        }
+
+      ypos = (parent.getSize().height - maxHeight) / 2 + insets.top;
+      xpos = insets.left + (parent.getSize().width - totalWidth) / 2;
+
+      for (int i = 0; i < comps.length; i++)
+        {
+         if (pref[i] == null)
+           continue;
+         comps[i].setBounds(xpos, ypos, pref[i].width, pref[i].height);
+         xpos += pref[i].width;
+        }
+    }
+
+    /**
+     * This method is called when a component is removed from the container.
+     *
+     * @param comp The component that was removed.
+     */
+    public void removeLayoutComponent(Component comp)
+    {
+    }
+
+    /**
+     * This methods calculates the minimum layout size for the container.
+     *
+     * @param parent The container.
+     *
+     * @return The minimum layout size.
+     */
+    public Dimension minimumLayoutSize(Container parent)
+    {
+      return preferredLayoutSize(parent);
+    }
+
+    /**
+     * This method returns the preferred layout size for the given container.
+     *
+     * @param parent The container.
+     *
+     * @return The preferred layout size.
+     */
+    public Dimension preferredLayoutSize(Container parent)
+    {
+      int xmax = 0;
+      int ymax = 0;
+
+      Component[] comps = parent.getComponents();
+      Dimension pref;
+
+      for (int i = 0; i < comps.length; i++)
+        {
+         pref = comps[i].getPreferredSize();
+         if (pref == null)
+           continue;
+         xmax += pref.width;
+         ymax = Math.max(ymax, pref.height);
+        }
+
+      Insets insets = parent.getInsets();
+
+      return new Dimension(insets.left + insets.right + xmax,
+                           insets.top + insets.bottom + ymax);
+    }
+  }
+
+  /**
+   * This is the layout manager for the recent swatch panel.
+   */
+  static class RecentPanelLayout implements LayoutManager
+  {
+    /**
+     * This method is called when a component is added to the container.
+     *
+     * @param name The name of the component.
+     * @param comp The added component.
+     */
+    public void addLayoutComponent(String name, Component comp)
+    {
+      // Nothing needs to be done.
+    }
+
+    /**
+     * This method sets the size and position of the child components of the
+     * given container.
+     *
+     * @param parent The container to lay out.
+     */
+    public void layoutContainer(Container parent)
+    {
+      Component[] comps = parent.getComponents();
+      Dimension parentSize = parent.getSize();
+      Insets insets = parent.getInsets();
+      int currY = insets.top;
+      Dimension pref;
+
+      for (int i = 0; i < comps.length; i++)
+        {
+         pref = comps[i].getPreferredSize();
+         if (pref == null)
+           continue;
+         comps[i].setBounds(insets.left, currY, pref.width, pref.height);
+         currY += pref.height;
+        }
+    }
+
+    /**
+     * This method calculates the minimum layout size for the given container.
+     *
+     * @param parent The container.
+     *
+     * @return The minimum layout size.
+     */
+    public Dimension minimumLayoutSize(Container parent)
+    {
+      return preferredLayoutSize(parent);
+    }
+
+    /**
+     * This method calculates the preferred layout size for the given
+     * container.
+     *
+     * @param parent The container.
+     *
+     * @return The preferred layout size.
+     */
+    public Dimension preferredLayoutSize(Container parent)
+    {
+      int width = 0;
+      int height = 0;
+      Insets insets = parent.getInsets();
+      Component[] comps = parent.getComponents();
+      Dimension pref;
+      for (int i = 0; i < comps.length; i++)
+        {
+         pref = comps[i].getPreferredSize();
+         if (pref != null)
+           {
+             width = Math.max(width, pref.width);
+             height += pref.height;
+           }
+        }
+
+      return new Dimension(width + insets.left + insets.right,
+                           height + insets.top + insets.bottom);
+    }
+
+    /**
+     * This method is called whenever a component is removed from the
+     * container.
+     *
+     * @param comp The removed component.
+     */
+    public void removeLayoutComponent(Component comp)
+    {
+      // Nothing needs to be done.
+    }
+  }
+
+  /**
+   * Creates a new DefaultSwatchChooserPanel object.
+   */
+  DefaultSwatchChooserPanel()
+  {
+    super();
+  }
+
+  /**
+   * This method updates the chooser panel with the new value from the
+   * JColorChooser.
+   */
+  public void updateChooser()
+  {
+  }
+
+  /**
+   * This method builds the chooser panel.
+   */
+  protected void buildChooser()
+  {
+    // The structure of the swatch panel is:
+    // One large panel (minus the insets).
+    // Inside that panel, there are two panels, one holds the palette.
+    // The other holds the label and the recent colors palette.
+    // The two palettes are two custom swatch panels.
+    setLayout(new MainPanelLayout());
+
+    JPanel mainPaletteHolder = new JPanel();
+    JPanel recentPaletteHolder = new JPanel();
+
+    mainPalette = new MainSwatchPanel();
+    recentPalette = new RecentSwatchPanel();
+    JLabel label = new JLabel("Recent:");
+
+    mouseHandler = new MouseHandler();
+    mainPalette.addMouseListener(mouseHandler);
+    recentPalette.addMouseListener(mouseHandler);
+
+    mainPaletteHolder.setLayout(new BorderLayout());
+    mainPaletteHolder.add(mainPalette, BorderLayout.CENTER);
+
+    recentPaletteHolder.setLayout(new RecentPanelLayout());
+    recentPaletteHolder.add(label);
+    recentPaletteHolder.add(recentPalette);
+
+    JPanel main = new JPanel();
+    main.add(mainPaletteHolder);
+    main.add(recentPaletteHolder);
+
+    this.add(main);
+  }
+
+  /**
+   * This method removes the chooser panel from the JColorChooser.
+   *
+   * @param chooser The JColorChooser this panel is being removed from.
+   */
+  public void uninstallChooserPanel(JColorChooser chooser)
+  {
+    recentPalette = null;
+    mainPalette = null;
+
+    removeAll();
+    super.uninstallChooserPanel(chooser);
+  }
+
+  /**
+   * This method returns the JTabbedPane displayed name.
+   *
+   * @return The name displayed in the JTabbedPane.
+   */
+  public String getDisplayName()
+  {
+    return "Swatches";
+  }
+
+  /**
+   * This method returns the small display icon.
+   *
+   * @return The small display icon.
+   */
+  public Icon getSmallDisplayIcon()
+  {
+    return null;
+  }
+
+  /**
+   * This method returns the large display icon.
+   *
+   * @return The large display icon.
+   */
+  public Icon getLargeDisplayIcon()
+  {
+    return null;
+  }
+
+  /**
+   * This method paints the chooser panel with the given Graphics object.
+   *
+   * @param g The Graphics object to paint with.
+   */
+  public void paint(Graphics g)
+  {
+    super.paint(g);
+  }
+
+  /**
+   * This method returns the tooltip text for the given MouseEvent.
+   *
+   * @param e The MouseEvent.
+   *
+   * @return The tooltip text.
+   */
+  public String getToolTipText(MouseEvent e)
+  {
+    return null;
+  }
+}
diff --git a/libjava/javax/swing/plaf/basic/BasicColorChooserUI.java b/libjava/javax/swing/plaf/basic/BasicColorChooserUI.java
new file mode 100644 (file)
index 0000000..1c2dcd6
--- /dev/null
@@ -0,0 +1,338 @@
+/* BasicColorChooserUI.java
+   Copyright (C) 2004 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+package javax.swing.plaf.basic;
+
+import java.awt.BorderLayout;
+import java.awt.Component;
+import java.awt.Container;
+import java.awt.Dimension;
+import java.awt.Insets;
+import java.awt.LayoutManager;
+import java.awt.Rectangle;
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+import javax.swing.JColorChooser;
+import javax.swing.JComponent;
+import javax.swing.JPanel;
+import javax.swing.JTabbedPane;
+import javax.swing.UIDefaults;
+import javax.swing.UIManager;
+import javax.swing.colorchooser.AbstractColorChooserPanel;
+import javax.swing.colorchooser.ColorChooserComponentFactory;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+import javax.swing.plaf.ColorChooserUI;
+import javax.swing.plaf.ComponentUI;
+
+
+/**
+ * This is the UI Class for the JColorChooser in the Basic Look and Feel.
+ */
+public class BasicColorChooserUI extends ColorChooserUI
+{
+  /**
+   * This helper class handles property changes from the JColorChooser.
+   */
+  public class PropertyHandler implements PropertyChangeListener
+  {
+    /**
+     * This method is called when any of the properties of the JColorChooser
+     * change.
+     *
+     * @param e The PropertyChangeEvent.
+     */
+    public void propertyChange(PropertyChangeEvent e)
+    {
+      if (e.getPropertyName() == JColorChooser.CHOOSER_PANELS_PROPERTY)
+       makeTabs(chooser.getChooserPanels());
+      else if (e.getPropertyName() == JColorChooser.PREVIEW_PANEL_PROPERTY)
+       updatePreviewPanel(chooser.getPreviewPanel());
+      else if (e.getPropertyName() == JColorChooser.SELECTION_MODEL_PROPERTY)
+       ((AbstractColorChooserPanel) pane.getSelectedComponent())
+       .updateChooser();
+
+      chooser.repaint();
+    }
+  }
+
+  /**
+   * This is a helper class that listens to the Model of the JColorChooser for
+   * color change events so it can update the preview panel.
+   */
+  private class PreviewListener implements ChangeListener
+  {
+    /**
+     * This method is called whenever the JColorChooser's color changes.
+     *
+     * @param e The ChangeEvent.
+     */
+    public void stateChanged(ChangeEvent e)
+    {
+      if (pane != null)
+        {
+         AbstractColorChooserPanel panel = (AbstractColorChooserPanel) pane
+                                           .getSelectedComponent();
+         if (panel != null)
+           panel.updateChooser();
+        }
+      chooser.repaint();
+    }
+  }
+
+  /**
+   * This helper class listens to the JTabbedPane that is used for tab
+   * changes.
+   */
+  private class TabPaneListener implements ChangeListener
+  {
+    /**
+     * This method is called whenever a different tab is selected in the
+     * JTabbedPane.
+     *
+     * @param e The ChangeEvent.
+     */
+    public void stateChanged(ChangeEvent e)
+    {
+      // Need to do this because we don't update all the tabs when they're not
+      // visible, so they are not informed of new colors when they're hidden.
+      AbstractColorChooserPanel comp = (AbstractColorChooserPanel) pane
+                                       .getSelectedComponent();
+      comp.updateChooser();
+    }
+  }
+
+  /** An array of default choosers to use in the JColorChooser. */
+  protected AbstractColorChooserPanel[] defaultChoosers;
+
+  /** The listener for the preview panel. */
+  protected ChangeListener previewListener;
+
+  /** The PropertyChangeListener for the JColorChooser. */
+  protected PropertyChangeListener propertyChangeListener;
+
+  /** The JColorChooser. */
+  private JColorChooser chooser;
+
+  /** The JTabbedPane that is used. */
+  private JTabbedPane pane;
+
+  /** The Container that holds the preview panel. */
+  private Container prevContainer;
+
+  /**
+   * Creates a new BasicColorChooserUI object.
+   */
+  public BasicColorChooserUI()
+  {
+    super();
+  }
+
+  /**
+   * This method creates a new UI Component for the given JComponent.
+   *
+   * @param c The JComponent to create an UI for.
+   *
+   * @return A new BasicColorChooserUI.
+   */
+  public static ComponentUI createUI(JComponent c)
+  {
+    return new BasicColorChooserUI();
+  }
+
+  /**
+   * This method creates the default chooser panels for the JColorChooser.
+   *
+   * @return The default chooser panels.
+   */
+  protected AbstractColorChooserPanel[] createDefaultChoosers()
+  {
+    return ColorChooserComponentFactory.getDefaultChooserPanels();
+  }
+
+  /**
+   * This method installs the UI Component for the given JComponent.
+   *
+   * @param c The JComponent to install this UI for.
+   */
+  public void installUI(JComponent c)
+  {
+    if (c instanceof JColorChooser)
+      {
+       chooser = (JColorChooser) c;
+       chooser.setLayout(new BorderLayout());
+
+       // Do this first, so we avoid doing work for property change events.
+       defaultChoosers = createDefaultChoosers();
+       chooser.setChooserPanels(defaultChoosers);
+       pane = new JTabbedPane();
+
+       pane.addChangeListener(new ChangeListener()
+           {
+             public void stateChanged(ChangeEvent e)
+             {
+               pane.repaint();
+             }
+           });
+
+       makeTabs(defaultChoosers);
+
+       chooser.add(pane, BorderLayout.NORTH);
+
+       installPreviewPanel();
+
+       installDefaults();
+       installListeners();
+      }
+  }
+
+  /**
+   * This method adds tabs to the JTabbedPane for the chooserPanels defined in
+   * the JColorChooser.
+   *
+   * @param panels The Panels that need tabs to be made for them.
+   */
+  private void makeTabs(AbstractColorChooserPanel[] panels)
+  {
+    pane.removeAll();
+    for (int i = 0; i < panels.length; i++)
+      pane.addTab(panels[i].getDisplayName(), panels[i].getSmallDisplayIcon(),
+                  panels[i]);
+  }
+
+  /**
+   * This method uninstalls this UI for the given JComponent.
+   *
+   * @param c The JComponent that will have this UI removed.
+   */
+  public void uninstallUI(JComponent c)
+  {
+    uninstallListeners();
+    uninstallDefaults();
+
+    pane = null;
+    chooser = null;
+  }
+
+  /**
+   * This method installs the preview panel for the JColorChooser.
+   */
+  protected void installPreviewPanel()
+  {
+    updatePreviewPanel(ColorChooserComponentFactory.getPreviewPanel());
+  }
+
+  /**
+   * This is a helper method that swaps the existing preview panel with the
+   * given panel.
+   *
+   * @param preview The new preview panel.
+   */
+  private void updatePreviewPanel(JComponent preview)
+  {
+    if (prevContainer == null)
+      {
+       prevContainer = new JPanel();
+       prevContainer.setLayout(new BorderLayout());
+       chooser.add(prevContainer, BorderLayout.CENTER);
+      }
+    prevContainer.removeAll();
+    prevContainer.add(preview, BorderLayout.CENTER);
+  }
+
+  /**
+   * This method installs the default properties given by the Basic Look and
+   * Feel.
+   */
+  protected void installDefaults()
+  {
+    UIDefaults defaults = UIManager.getLookAndFeelDefaults();
+
+    chooser.setFont(defaults.getFont("ColorChooser.font"));
+    chooser.setForeground(defaults.getColor("ColorChooser.foreground"));
+    chooser.setBackground(defaults.getColor("ColorChooser.background"));
+  }
+
+  /**
+   * This method uninstalls the default properties given by the Basic Look and
+   * Feel.
+   */
+  protected void uninstallDefaults()
+  {
+    chooser.setBackground(null);
+    chooser.setForeground(null);
+    chooser.setFont(null);
+  }
+
+  /**
+   * This method installs any listeners required for this UI to function.
+   */
+  protected void installListeners()
+  {
+    propertyChangeListener = createPropertyChangeListener();
+    previewListener = new PreviewListener();
+
+    chooser.addPropertyChangeListener(propertyChangeListener);
+    chooser.getSelectionModel().addChangeListener(previewListener);
+
+    pane.addChangeListener(new TabPaneListener());
+  }
+
+  /**
+   * This method creates the PropertyChangeListener used for listening to the
+   * JColorChooser.
+   *
+   * @return A PropertyChangeListener.
+   */
+  protected PropertyChangeListener createPropertyChangeListener()
+  {
+    return new PropertyHandler();
+  }
+
+  /**
+   * This method uninstalls any listeners that were previously installed by
+   * the UI.
+   */
+  protected void uninstallListeners()
+  {
+    chooser.removePropertyChangeListener(propertyChangeListener);
+    chooser.getSelectionModel().removeChangeListener(previewListener);
+
+    previewListener = null;
+    propertyChangeListener = null;
+  }
+}
diff --git a/libjava/javax/swing/plaf/basic/BasicComboBoxEditor.java b/libjava/javax/swing/plaf/basic/BasicComboBoxEditor.java
new file mode 100644 (file)
index 0000000..a465ff9
--- /dev/null
@@ -0,0 +1,170 @@
+/* BasicComboBoxEditor.java --
+   Copyright (C) 2004  Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+package javax.swing.plaf.basic;
+
+import java.awt.Component;
+import java.awt.event.ActionListener;
+import java.awt.event.FocusEvent;
+import java.awt.event.FocusListener;
+import javax.swing.ComboBoxEditor;
+import javax.swing.JTextField;
+import javax.swing.border.EmptyBorder;
+import javax.swing.plaf.UIResource;
+
+
+/**
+ * This is a component that is responsible for displaying/editting  selected
+ * item in comboBox. By default, the  JTextField is returned as
+ * BasicComboBoxEditor.
+ *
+ * @author Olga Rodimina
+ */
+public class BasicComboBoxEditor extends Object implements ComboBoxEditor,
+                                                           FocusListener
+{
+  protected JTextField editor;
+
+  /**
+   * Creates a new BasicComboBoxEditor object.
+   */
+  public BasicComboBoxEditor()
+  {
+    editor = new JTextField();
+    editor.setBorder(new EmptyBorder(1, 1, 1, 1));
+  }
+
+  /**
+   * This method returns textfield that will be used by the combo  box to
+   * display/edit currently selected item in the combo box.
+   *
+   * @return textfield that will be used by the combo box to  display/edit
+   *         currently selected item
+   */
+  public Component getEditorComponent()
+  {
+    return editor;
+  }
+
+  /**
+   * Sets item that should be editted when any editting operation is performed
+   * by the user. The value is always equal to the currently selected value
+   * in the combo box. Thus whenever a different value is selected from the
+   * combo box list then this method should be  called to change editting
+   * item to the new selected item.
+   *
+   * @param selectedItem item that is currently selected in the combo box
+   */
+  public void setItem(Object item)
+  {
+    editor.setText(item.toString());
+  }
+
+  /**
+   * This method returns item that is currently editable.
+   *
+   * @return item in the combo box that is currently editable
+   */
+  public Object getItem()
+  {
+    return editor.getText();
+  }
+
+  public void selectAll()
+  {
+    editor.selectAll();
+  }
+
+  /**
+   * This method is called when textfield gains focus. This will enable
+   * editing of the selected item.
+   *
+   * @param e the FocusEvent describing change in focus.
+   */
+  public void focusGained(FocusEvent e)
+  {
+    // FIXME: Need to implement
+  }
+
+  /**
+   * This method is called when textfield loses focus. If during this time any
+   * editting operation was performed by the user, then it will be cancelled
+   * and selected item will not be changed.
+   *
+   * @param e the FocusEvent describing change in focus
+   */
+  public void focusLost(FocusEvent e)
+  {
+    // FIXME: Need to implement
+  }
+
+  /**
+   * This method adds actionListener to the editor. If the user will edit
+   * currently selected item in the textfield and pressEnter, then action
+   * will be performed. The actionPerformed of this ActionListener should
+   * change the selected item of the comboBox to the newly editted  selected
+   * item.
+   *
+   * @param l the ActionListener responsible for changing selected item of the
+   *        combo box when it is editted by the user.
+   */
+  public void addActionListener(ActionListener l)
+  {
+    // FIXME: Need to implement
+  }
+
+  /**
+   * This method removes actionListener from the textfield.
+   *
+   * @param l the ActionListener to remove from the textfield.
+   */
+  public void removeActionListener(ActionListener l)
+  {
+    // FIXME: Need to implement
+  }
+
+  public static class UIResource extends BasicComboBoxEditor
+    implements javax.swing.plaf.UIResource
+  {
+    /**
+     * Creates a new UIResource object.
+     */
+    public UIResource()
+    {
+    }
+  }
+}
diff --git a/libjava/javax/swing/plaf/basic/BasicComboBoxRenderer.java b/libjava/javax/swing/plaf/basic/BasicComboBoxRenderer.java
new file mode 100644 (file)
index 0000000..6bf6a74
--- /dev/null
@@ -0,0 +1,143 @@
+/* BasicComboBoxRenderer.java --
+   Copyright (C) 2004  Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+package javax.swing.plaf.basic;
+
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Dimension;
+import java.io.Serializable;
+import javax.swing.JLabel;
+import javax.swing.JList;
+import javax.swing.ListCellRenderer;
+import javax.swing.SwingConstants;
+import javax.swing.UIDefaults;
+import javax.swing.UIManager;
+import javax.swing.border.Border;
+import javax.swing.border.EmptyBorder;
+import javax.swing.plaf.UIResource;
+
+
+/**
+ * This class is renderer for the combo box. 
+ *
+ * @author Olga Rodimina
+ */
+public class BasicComboBoxRenderer extends JLabel implements ListCellRenderer,
+                                                             Serializable
+{
+  /**
+   * This border is used whenever renderer doesn't have a focus.
+   */
+  protected static Border noFocusBorder = new EmptyBorder(0, 0, 0, 0);
+
+  /**
+   * Creates a new BasicComboBoxRenderer object.
+   */
+  public BasicComboBoxRenderer()
+  {
+    setHorizontalAlignment(SwingConstants.LEFT);
+  }
+
+  /**
+   * Returns preferredSize of the renderer
+   *
+   * @return preferredSize of the renderer
+   */
+  public Dimension getPreferredSize()
+  {
+    return super.getPreferredSize();
+  }
+
+  /**
+   * getListCellRendererComponent
+   *
+   * @param list List of items for which to the background and foreground
+   *        colors
+   * @param value object that should be rendered in the cell
+   * @param index index of the cell in the list of items.
+   * @param isSelected draw cell highlighted if isSelected is true
+   * @param cellHasFocus draw focus rectangle around cell if the cell has
+   *        focus
+   *
+   * @return Component that will be used to draw the desired cell.
+   */
+  public Component getListCellRendererComponent(JList list, Object value,
+                                                int index, boolean isSelected,
+                                                boolean cellHasFocus)
+  {
+    String s = value.toString();
+    setText(s);
+    setOpaque(true);
+
+    UIDefaults defaults = UIManager.getLookAndFeelDefaults();
+
+    if (isSelected)
+      {
+       setBackground(list.getSelectionBackground());
+       setForeground(list.getSelectionForeground());
+      }
+    else
+      {
+       setBackground(list.getBackground());
+       setForeground(list.getForeground());
+      }
+
+    setEnabled(list.isEnabled());
+    setFont(list.getFont());
+
+    // Use focusCellHighlightBorder when renderer has focus and 
+    // noFocusBorder otherwise
+    if (cellHasFocus)
+      setBorder(UIManager.getBorder("List.focusCellHighlightBorder"));
+    else
+      setBorder(noFocusBorder);
+
+    return this;
+  }
+
+  public static class UIResource extends BasicComboBoxRenderer
+    implements javax.swing.plaf.UIResource
+  {
+    /**
+     * Creates a new UIResource object.
+     */
+    public UIResource()
+    {
+    }
+  }
+}
diff --git a/libjava/javax/swing/plaf/basic/BasicComboBoxUI.java b/libjava/javax/swing/plaf/basic/BasicComboBoxUI.java
new file mode 100644 (file)
index 0000000..851392a
--- /dev/null
@@ -0,0 +1,1227 @@
+/* BasicComboBoxUI.java --
+   Copyright (C) 2004  Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+package javax.swing.plaf.basic;
+
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Container;
+import java.awt.Dimension;
+import java.awt.Graphics;
+import java.awt.Insets;
+import java.awt.LayoutManager;
+import java.awt.Rectangle;
+import java.awt.event.FocusEvent;
+import java.awt.event.FocusListener;
+import java.awt.event.ItemEvent;
+import java.awt.event.ItemListener;
+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.EventListener;
+import javax.accessibility.Accessible;
+import javax.swing.CellRendererPane;
+import javax.swing.ComboBoxEditor;
+import javax.swing.ComboBoxModel;
+import javax.swing.JButton;
+import javax.swing.JComboBox;
+import javax.swing.JComponent;
+import javax.swing.JLabel;
+import javax.swing.JList;
+import javax.swing.ListCellRenderer;
+import javax.swing.SwingConstants;
+import javax.swing.UIDefaults;
+import javax.swing.UIManager;
+import javax.swing.event.ListDataEvent;
+import javax.swing.event.ListDataListener;
+import javax.swing.event.PopupMenuEvent;
+import javax.swing.event.PopupMenuListener;
+import javax.swing.plaf.ComboBoxUI;
+import javax.swing.plaf.ComponentUI;
+import javax.swing.plaf.basic.BasicComboPopup;
+import javax.swing.plaf.basic.BasicGraphicsUtils;
+
+
+/**
+ * UI Delegate for JComboBox
+ *
+ * @author Olga Rodimina
+ */
+public class BasicComboBoxUI extends ComboBoxUI
+{
+  /**
+   * This arrow button that is displayed in the rigth side of JComboBox. This
+   * button is used to hide and show combo box's list of items
+   */
+  protected JButton arrowButton;
+
+  /**
+   * The combo box for which this UI delegate is for
+   */
+  protected JComboBox comboBox;
+
+  /**
+   * Component that is responsible for displaying/editting  selected item of
+   * the combo box. By default JTextField is used as an editor for the
+   * JComboBox
+   */
+  protected Component editor;
+
+  /**
+   * Listener listening to focus events occuring in the JComboBox
+   */
+  protected FocusListener focusListener;
+
+  /**
+   * tells whether JComboBox currently has focus
+   */
+  protected boolean hasFocus;
+
+  /**
+   * Listener listening to item events fired by the JComboBox
+   */
+  protected ItemListener itemListener;
+
+  /**
+   * KeyListener listening to key events that occur while JComboBox has focus
+   */
+  protected KeyListener keyListener;
+
+  /**
+   * MouseListener listening to mouse events occuring in the combo box
+   */
+  private MouseListener mouseListener;
+
+  /**
+   * List used when rendering selected item of the combo box. The selection
+   * and foreground colors for combo box renderer  are configured from this
+   * list
+   */
+  protected JList listBox;
+
+  /**
+   * ListDataListener listening to JComboBox model
+   */
+  protected ListDataListener listDataListener;
+
+  /**
+   * Popup list containing combo box's menu items
+   */
+  protected ComboPopup popup;
+  protected KeyListener popupKeyListener;
+  protected MouseListener popupMouseListener;
+  protected MouseMotionListener popupMouseMotionListener;
+
+  /**
+   * Listener listening to changes in the bound properties of JComboBox
+   */
+  protected PropertyChangeListener propertyChangeListener;
+
+  /**
+   * Colors that are used to render selected item in the combo box.
+   */
+  private Color shadow;
+  private Color darkShadow;
+  private Color highlight;
+  private Color lightHighlight;
+
+  /* Size of the largest item in the comboBox */
+  private Dimension largestItemSize;
+
+  // It seems that JComboBox doesn't have a border set explicitely. So we just
+  // paint the border everytime combo box is displayed. 
+
+  /* border insets for this JComboBox*/
+  private static final Insets borderInsets = new Insets(2, 2, 2, 2);
+
+  // Width of the arrow button  
+  private static int arrowButtonWidth = 15;
+
+  // FIXME: This fields aren't used anywhere at this moment.
+  protected Dimension cachedMinimumSize;
+  protected CellRendererPane currentValuePane;
+  protected boolean isMinimumSizeDirty;
+
+  /**
+   * Creates a new BasicComboBoxUI object.
+   */
+  public BasicComboBoxUI()
+  {
+  }
+
+  /**
+   * Factory method to create a BasicComboBoxUI for the given {@link
+   * JComponent}, which should be a {@link JComboBox}.
+   *
+   * @param c The {@link JComponent} a UI is being created for.
+   *
+   * @return A BasicComboBoxUI for the {@link JComponent}.
+   */
+  public static ComponentUI createUI(JComponent c)
+  {
+    return new BasicComboBoxUI();
+  }
+
+  /**
+   * 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 JComboBox)
+      {
+       comboBox = (JComboBox) c;
+       comboBox.setOpaque(true);
+       comboBox.setLayout(createLayoutManager());
+       installDefaults();
+       installComponents();
+       installListeners();
+       installKeyboardActions();
+      }
+  }
+
+  /**
+   * This method uninstalls the UI.
+   *
+   * @param c The JComponent that is having this UI removed.
+   */
+  public void uninstallUI(JComponent c)
+  {
+    uninstallKeyboardActions();
+    uninstallListeners();
+    uninstallComponents();
+    uninstallDefaults();
+    comboBox = null;
+  }
+
+  /**
+   * This method installs the defaults that are defined in  the Basic look and
+   * feel for this {@link JComboBox}.
+   */
+  protected void installDefaults()
+  {
+    UIDefaults defaults = UIManager.getLookAndFeelDefaults();
+
+    comboBox.setBackground(defaults.getColor("ComboBox.background"));
+    comboBox.setFont(defaults.getFont("ComboBox.font"));
+    comboBox.setForeground(defaults.getColor("ComboBox.foreground"));
+
+    // Set default color that should be used to to render selected item
+    // of the combo box.
+    shadow = defaults.getColor("Button.shadow");
+    darkShadow = defaults.getColor("Button.darkShadow");
+    lightHighlight = defaults.getColor("Button.light");
+    highlight = defaults.getColor("Button.highlight");
+  }
+
+  /**
+   * This method creates and installs the listeners for this UI.
+   */
+  protected void installListeners()
+  {
+    // install combo box's listeners
+    propertyChangeListener = createPropertyChangeListener();
+    comboBox.addPropertyChangeListener(propertyChangeListener);
+
+    focusListener = createFocusListener();
+    comboBox.addFocusListener(focusListener);
+
+    itemListener = createItemListener();
+    comboBox.addItemListener(itemListener);
+
+    keyListener = createKeyListener();
+    comboBox.addKeyListener(keyListener);
+
+    mouseListener = createMouseListener();
+    comboBox.addMouseListener(mouseListener);
+
+    // install listeners that listen to combo box model
+    listDataListener = createListDataListener();
+    comboBox.getModel().addListDataListener(listDataListener);
+
+    configureArrowButton();
+  }
+
+  /**
+   * This method uninstalls the defaults and sets any objects created during
+   * install to null
+   */
+  protected void uninstallDefaults()
+  {
+    UIDefaults defaults = UIManager.getLookAndFeelDefaults();
+
+    comboBox.setBackground(null);
+    comboBox.setFont(null);
+    comboBox.setForeground(null);
+
+    shadow = null;
+    darkShadow = null;
+    lightHighlight = null;
+    highlight = null;
+  }
+
+  /**
+   * Detaches all the listeners we attached in {@link #installListeners}.
+   */
+  protected void uninstallListeners()
+  {
+    comboBox.removePropertyChangeListener(propertyChangeListener);
+    propertyChangeListener = null;
+
+    comboBox.removeFocusListener(focusListener);
+    focusListener = null;
+
+    comboBox.removeItemListener(itemListener);
+    itemListener = null;
+
+    comboBox.removeKeyListener(keyListener);
+    keyListener = null;
+
+    comboBox.removeMouseListener(mouseListener);
+    mouseListener = null;
+
+    comboBox.getModel().removeListDataListener(listDataListener);
+    listDataListener = null;
+
+    unconfigureArrowButton();
+  }
+
+  /**
+   * This method creates popup that will contain list of combo box's items
+   *
+   * @return popup containing list of combo box's items
+   */
+  protected ComboPopup createPopup()
+  {
+    return new BasicComboPopup(comboBox);
+  }
+
+  /**
+   * Creates KeyListener to listen to key events.
+   *
+   * @return KeyListener that listens to key events.
+   */
+  protected KeyListener createKeyListener()
+  {
+    return new KeyHandler();
+  }
+
+  /**
+   * This method create MouseListener that will listen to mouse event occuring
+   * in combo box.
+   *
+   * @return the MouseListener
+   */
+  private MouseListener createMouseListener()
+  {
+    return new MouseHandler();
+  }
+
+  /**
+   * This method create FocusListener that will listen to changes in this
+   * JComboBox's focus.
+   *
+   * @return theFocusListener
+   */
+  protected FocusListener createFocusListener()
+  {
+    return new FocusHandler();
+  }
+
+  /**
+   * This method create ListDataListener to listen to ComboBox's  data model
+   *
+   * @return ListDataListener
+   */
+  protected ListDataListener createListDataListener()
+  {
+    return new ListDataHandler();
+  }
+
+  /**
+   * This method creates ItemListener that will listen to to the changes in
+   * the JComboBox's selection.
+   *
+   * @return the ItemListener
+   */
+  protected ItemListener createItemListener()
+  {
+    return new ItemHandler();
+  }
+
+  /**
+   * This method creates PropertyChangeListener to listen to  the changes in
+   * the JComboBox's bound properties.
+   *
+   * @return the PropertyChangeListener
+   */
+  protected PropertyChangeListener createPropertyChangeListener()
+  {
+    return new PropertyChangeHandler();
+  }
+
+  /**
+   * This method returns layout manager for the combo box.
+   *
+   * @return layout manager for the combo box
+   */
+  protected LayoutManager createLayoutManager()
+  {
+    return new ComboBoxLayoutManager();
+  }
+
+  /**
+   * This method creates component that will be responsible for rendering the
+   * selected component in the combo box.
+   *
+   * @return render for the combo box
+   */
+  protected ListCellRenderer createRenderer()
+  {
+    return new BasicComboBoxRenderer();
+  }
+
+  /**
+   * Creates component that will be responsible for displaying/editting
+   * selected item in the combo box. This editor is used only when combo box
+   * is editable.
+   *
+   * @return component that will be responsible for  displaying/editting
+   *         selected item in the combo box.
+   */
+  protected ComboBoxEditor createEditor()
+  {
+    return new BasicComboBoxEditor();
+  }
+
+  /**
+   * This method installs components for this JComboBox. ArrowButton, main
+   * part of combo box (upper part) and  popup list of items are created and
+   * configured here.
+   */
+  protected void installComponents()
+  {
+    // create and install arrow button
+    arrowButton = createArrowButton();
+
+    comboBox.add(arrowButton);
+
+    // Set list that will be used by BasicComboBoxRender 
+    // in order to determine the right colors when rendering
+    listBox = new JList();
+
+    Color background = arrowButton.getBackground();
+    listBox.setBackground(background);
+    listBox.setSelectionBackground(background.darker());
+
+    Color foreground = arrowButton.getForeground();
+    listBox.setForeground(foreground);
+    listBox.setSelectionForeground(foreground);
+
+    // set editor and renderer for the combo box. Editor is used
+    // only if combo box becomes editable, otherwise renderer is used
+    // to paint the selected item; combobox is not editable by default. 
+    comboBox.setRenderer(createRenderer());
+
+    comboBox.setEditor(createEditor());
+    editor = comboBox.getEditor().getEditorComponent();
+
+    // create drop down list of items
+    popup = createPopup();
+
+    comboBox.revalidate();
+  }
+
+  /**
+   * This method uninstalls components from this JComboBox
+   */
+  protected void uninstallComponents()
+  {
+    // uninstall arrow button
+    unconfigureArrowButton();
+    comboBox.remove(arrowButton);
+    arrowButton = null;
+
+    listBox = null;
+    popup = null;
+
+    comboBox.setRenderer(null);
+
+    comboBox.setEditor(null);
+    editor = null;
+  }
+
+  /**
+   * This method adds editor to the combo box
+   */
+  public void addEditor()
+  {
+    comboBox.add(editor);
+  }
+
+  /**
+   * This method removes editor from the combo box
+   */
+  public void removeEditor()
+  {
+    comboBox.remove(editor);
+  }
+
+  /**
+   * This method configures editor for this combo box.
+   */
+  protected void configureEditor()
+  {
+    // FIXME: Need to implement. Set font and add listeners.
+  }
+
+  /**
+   * This method removes all the listeners for the editor.
+   */
+  protected void unconfigureEditor()
+  {
+    // FIXME: Need to implement    
+  }
+
+  /**
+   * This method adds listeners to the arrow button part of the combo box.
+   */
+  public void configureArrowButton()
+  {
+    arrowButton.addMouseListener(mouseListener);
+  }
+
+  /**
+   * This method removes listeners from the arrow button part of the combo
+   * box.
+   */
+  public void unconfigureArrowButton()
+  {
+    arrowButton.removeMouseListener(mouseListener);
+  }
+
+  /**
+   * This method create arrow button for this JComboBox. Arrow button is
+   * responsible for displaying / hiding drop down list of items  when it is
+   * clicked.
+   *
+   * @return JButton arrow button for this JComboBox.
+   */
+  protected JButton createArrowButton()
+  {
+    return new BasicArrowButton(BasicArrowButton.SOUTH);
+  }
+
+  /**
+   * This method checks if popup part of the combo box is visible on the
+   * screen
+   *
+   * @param c The JComboBox to check
+   *
+   * @return true if popup part of the JComboBox is visible and false
+   *         otherwise.
+   */
+  public boolean isPopupVisible(JComboBox c)
+  {
+    return popup.isVisible();
+  }
+
+  /**
+   * Displays/Hides JComboBox's list of items on the screen.
+   *
+   * @param c The combo box, for which list of items should be
+   *        displayed/hidden
+   * @param v true if show popup part of the jcomboBox and false to hide.
+   */
+  public void setPopupVisible(JComboBox c, boolean v)
+  {
+    if (v)
+      popup.show();
+    else
+      popup.hide();
+  }
+
+  /**
+   * JComboBox is focus traversable if it is editable and not otherwise.
+   *
+   * @param c combo box for which to check whether it is focus traversable
+   *
+   * @return true if focus tranversable and false otherwise
+   */
+  public boolean isFocusTraversable(JComboBox c)
+  {
+    if (comboBox.isEditable())
+      return true;
+
+    return false;
+  }
+
+  /**
+   * Paints given menu item using specified graphics context
+   *
+   * @param g The graphics context used to paint this combo box
+   * @param c comboBox which needs to be painted.
+   */
+  public void paint(Graphics g, JComponent c)
+  {
+    if (c instanceof JComboBox)
+      {
+       JComboBox cb = (JComboBox) c;
+
+       paintBorder(g, comboBox.getBounds(), hasFocus);
+
+       Rectangle rect = rectangleForCurrentValue();
+       paintCurrentValueBackground(g, rect, hasFocus);
+       paintCurrentValue(g, rect, hasFocus);
+      }
+  }
+
+  private void paintBorder(Graphics g, Rectangle bounds, boolean hasFocus)
+  {
+    int x = 0;
+    int y = 0;
+    int width = bounds.width;
+    int height = bounds.height;
+
+    Color oldColor = g.getColor();
+
+    if (! arrowButton.getModel().isPressed())
+      BasicGraphicsUtils.drawEtchedRect(g, x, y, width, height, Color.gray,
+                                        Color.white, Color.gray, Color.white);
+    else
+      {
+       g.setColor(darkShadow);
+       g.drawRect(x, y, width, height);
+       g.setColor(shadow);
+       g.drawRect(x + 1, y + 1, width - 3, height - 3);
+      }
+    g.setColor(oldColor);
+  }
+
+  /**
+   * Returns preferred size for the given menu item.
+   *
+   * @param c comboBox for which to get preferred size
+   *
+   * @return $Dimension$ preferred size for the given combo box
+   */
+  public Dimension getPreferredSize(JComponent c)
+  {
+    // return null to indicate that combo box's layout will determin its
+    // preferred size
+    return null;
+  }
+
+  /**
+   * This method returns the minimum size for this {@link JComboBox} for this
+   * look and feel.
+   *
+   * @param c The {@link JComponent} to find the minimum size for.
+   *
+   * @return The dimensions of the minimum size.
+   */
+  public Dimension getMinimumSize(JComponent c)
+  {
+    return null;
+  }
+
+  /**
+   * This method returns the maximum size for this {@link JComboBox} for this
+   * look and feel.
+   *
+   * @param c The {@link JComponent} to find the maximum size for
+   *
+   * @return The dimensions of the minimum size.
+   */
+  public Dimension getMaximumSize(JComponent c)
+  {
+    return null;
+  }
+
+  public int getAccessibleChildrenCount(JComponent c)
+  {
+    // FIXME: Need to implement
+    return 0;
+  }
+
+  public Accessible getAccessibleChild(JComponent c, int i)
+  {
+    // FIXME: Need to implement
+    return null;
+  }
+
+  /**
+   * Returns true if the specified key is a navigation key and false otherwise
+   *
+   * @param keyCode a key for which to check whether it is navigation key or
+   *        not.
+   *
+   * @return true if the specified key is a navigation key and false otherwis
+   */
+  protected boolean isNavigationKey(int keyCode)
+  {
+    return false;
+  }
+
+  /**
+   * This method selects next possible item relative to the current selection
+   * to be next selected item in the combo box.
+   */
+  protected void selectNextPossibleValue()
+  {
+    int index = comboBox.getSelectedIndex();
+    if (index != comboBox.getItemCount() - 1)
+      comboBox.setSelectedIndex(index + 1);
+  }
+
+  /**
+   * This method selects previous item relative to current selection to be
+   * next selected item.
+   */
+  protected void selectPreviousPossibleValue()
+  {
+    int index = comboBox.getSelectedIndex();
+    if (index != 0)
+      comboBox.setSelectedIndex(index - 1);
+  }
+
+  /**
+   * This method displays combo box popup if the popup is not currently shown
+   * on the screen and hides it if it is  currently shown
+   */
+  protected void toggleOpenClose()
+  {
+    setPopupVisible(comboBox, ! isPopupVisible(comboBox));
+  }
+
+  /**
+   * This method returns bounds in which comboBox's selected Item will be
+   * displayed
+   *
+   * @return rectangle bounds in which comboBox's selected Item will be
+   *         displayed
+   */
+  protected Rectangle rectangleForCurrentValue()
+  {
+    Rectangle cbBounds = comboBox.getBounds();
+
+    // Subtract width or the arrow button and border insets        
+    Rectangle rectForCurrentValue = new Rectangle(cbBounds.x
+                                                  + borderInsets.left,
+                                                  cbBounds.y
+                                                  + borderInsets.top,
+                                                  cbBounds.width
+                                                  - arrowButtonWidth
+                                                  - borderInsets.left
+                                                  - borderInsets.right,
+                                                  cbBounds.height
+                                                  - borderInsets.top
+                                                  - borderInsets.bottom);
+
+    return rectForCurrentValue;
+  }
+
+  /**
+   * This method returns insets of the current border.
+   *
+   * @return Insets representing space between combo box and its border
+   */
+  protected Insets getInsets()
+  {
+    return new Insets(0, 0, 0, 0);
+  }
+
+  /**
+   * This method paints currently selected value in the main part of the combo
+   * box (part without popup).
+   *
+   * @param g graphics context
+   * @param bounds Rectangle representing the size of the area in which
+   *        selected item should be drawn
+   * @param hasFocus true if combo box has focus and false otherwise
+   */
+  public void paintCurrentValue(Graphics g, Rectangle bounds, boolean hasFocus)
+  {
+    if (! comboBox.isEditable())
+      {
+       Object currentValue = comboBox.getSelectedItem();
+       boolean isPressed = arrowButton.getModel().isPressed();
+       if (currentValue != null)
+         {
+           Component comp = comboBox.getRenderer()
+                                    .getListCellRendererComponent(listBox,
+                                                                  currentValue,
+                                                                  -1,
+                                                                  isPressed,
+                                                                  isPressed);
+           if (! comboBox.isEnabled())
+             comp.setEnabled(false);
+
+           g.translate(borderInsets.left, borderInsets.top);
+           comp.setBounds(0, 0, bounds.width, bounds.height);
+           comp.paint(g);
+           g.translate(-borderInsets.left, -borderInsets.top);
+         }
+       comboBox.revalidate();
+      }
+    else
+      comboBox.getEditor().setItem(comboBox.getSelectedItem());
+  }
+
+  /**
+   * This method paints background of part of the combo box, where currently
+   * selected value is displayed. If the combo box has focus this method
+   * should also paint focus rectangle around the combo box.
+   *
+   * @param g graphics context
+   * @param bounds Rectangle representing the size of the largest item  in the
+   *        comboBox
+   * @param hasFocus true if combo box has fox and false otherwise
+   */
+  public void paintCurrentValueBackground(Graphics g, Rectangle bounds,
+                                          boolean hasFocus)
+  {
+    // background is painted by renderer, so it seems that nothing
+    // should be done here.
+  }
+
+  /**
+   * Returns default size for the combo box that doesn't contain any elements
+   * in it
+   *
+   * @return Default size of the combo box with no elements in it.
+   */
+  protected Dimension getDefaultSize()
+  {
+    return new Dimension(6, 17);
+  }
+
+  /**
+   * Returns size of the largest item in the combo box. This size will be the
+   * size of the combo box, not including the arrowButton.
+   *
+   * @return dimensions of the largest item in the combo box.
+   */
+  protected Dimension getLargestItemSize()
+  {
+    ComboBoxModel model = comboBox.getModel();
+    int numItems = model.getSize();
+
+    // if combo box doesn't have any items then simply
+    // return its default size
+    if (numItems == 0)
+      {
+       largestItemSize = getDefaultSize();
+       return largestItemSize;
+      }
+
+    Dimension size = new Dimension(0, 0);
+
+    // ComboBox's display size should be equal to the 
+    // size of the largest item in the combo box. 
+    ListCellRenderer renderer = comboBox.getRenderer();
+
+    for (int i = 0; i < numItems; i++)
+      {
+       Object item = model.getElementAt(i);
+       String s = item.toString();
+       Component comp = renderer.getListCellRendererComponent(listBox, item,
+                                                              -1, false, false);
+
+       if (comp.getPreferredSize().getWidth() > size.getWidth())
+         size = comp.getPreferredSize();
+      }
+
+    largestItemSize = size;
+    return largestItemSize;
+  }
+
+  /**
+   * This method installs the keyboard actions for the JComboBox as specified
+   * by the look and feel.
+   */
+  protected void installKeyboardActions()
+  {
+    // FIXME: Need to implement.
+  }
+
+  /**
+   * This method uninstalls the keyboard actions for the JComboBox there were
+   * installed by in {@link #installListeners}.
+   */
+  protected void uninstallKeyboardActions()
+  {
+    // FIXME: Need to implement.
+  }
+
+  /**
+   * This class is Layout Manager for this combo box.
+   */
+  public class ComboBoxLayoutManager extends Object implements LayoutManager
+  {
+    /**
+     * Creates a new ComboBoxLayoutManager object.
+     */
+    public ComboBoxLayoutManager()
+    {
+    }
+
+    public void addLayoutComponent(String name, Component comp)
+    {
+      // Do nothing
+    }
+
+    public void removeLayoutComponent(Component comp)
+    {
+      // Do nothing
+    }
+
+    /**
+     * Returns preferred layout size of the JComboBox.
+     *
+     * @param parent Container for which preferred size should be calculated
+     *
+     * @return preferred size for the given container
+     */
+    public Dimension preferredLayoutSize(Container parent)
+    {
+      Dimension d = new Dimension(0, 0);
+
+      if (largestItemSize == null)
+       largestItemSize = getLargestItemSize();
+
+      // add size for the area that will display selected item
+      d.width += largestItemSize.getWidth();
+      d.height += largestItemSize.getHeight();
+
+      // add size of the arrow button
+      d.width += arrowButtonWidth;
+
+      // add width and height of the border
+      d.width += borderInsets.left + borderInsets.right;
+      d.height += borderInsets.left + borderInsets.right;
+
+      // Add combo box's insets        
+      Insets insets = parent.getInsets();
+      d.width += insets.left + insets.right;
+      d.width += insets.left + insets.right;
+
+      return d;
+    }
+
+    public Dimension minimumLayoutSize(Container parent)
+    {
+      return preferredLayoutSize(parent);
+    }
+
+    /**
+     * This method layouts out the components in the container.  It puts arrow
+     * button right end part of the comboBox. If the comboBox is editable
+     * then editor is placed to the left of arrow  button, starting from the
+     * beginning.
+     *
+     * @param parent Container that should be layed out.
+     */
+    public void layoutContainer(Container parent)
+    {
+      // Position editor component to the left of arrow button if combo box is 
+      // editable
+      int editorWidth = comboBox.getBounds().width - arrowButtonWidth - 2;
+
+      if (comboBox.isEditable())
+       editor.setBounds(borderInsets.left, borderInsets.top, editorWidth,
+                        comboBox.getBounds().height - borderInsets.left
+                        - borderInsets.top);
+
+      arrowButton.setBounds(editorWidth, 2, arrowButtonWidth,
+                            comboBox.getBounds().height - 4);
+      comboBox.revalidate();
+    }
+  }
+
+  /**
+   * This class handles focus changes occuring in the combo box. This class is
+   * responsible for repainting combo box whenever focus is gained or lost
+   * and also for hiding popup list of items whenever combo box loses its
+   * focus.
+   */
+  public class FocusHandler extends Object implements FocusListener
+  {
+    /**
+     * Creates a new FocusHandler object.
+     */
+    public FocusHandler()
+    {
+    }
+
+    /**
+     * This mehtod is invoked when combo box gains focus. It repaints main
+     * part of combo box  accordingally.
+     *
+     * @param e the FocusEvent
+     */
+    public void focusGained(FocusEvent e)
+    {
+      hasFocus = true;
+      comboBox.repaint();
+    }
+
+    /**
+     * This method is invoked when combo box loses focus It repaint main part
+     * of combo box accordingally and  hides popup list of items.
+     *
+     * @param e the FocusEvent
+     */
+    public void focusLost(FocusEvent e)
+    {
+      hasFocus = false;
+      comboBox.repaint();
+      popup.hide();
+    }
+  }
+
+  /**
+   * This class handles ItemEvent fired by the JComboBox when its selected
+   * item changes.
+   */
+  public class ItemHandler extends Object implements ItemListener
+  {
+    /**
+     * Creates a new ItemHandler object.
+     */
+    public ItemHandler()
+    {
+    }
+
+    /**
+     * This method is invoked when selected item becomes deselected or when
+     * new item becomes selected.
+     *
+     * @param e the ItemEvent representing item's state change.
+     */
+    public void itemStateChanged(ItemEvent e)
+    {
+      comboBox.repaint();
+    }
+  }
+
+  /**
+   * KeyHandler handles key events occuring while JComboBox has focus.
+   */
+  public class KeyHandler extends KeyAdapter
+  {
+    public KeyHandler()
+    {
+    }
+
+    /*
+     * This method is invoked whenever key is pressed while JComboBox is in
+     * focus.
+     */
+    public void keyPressed(KeyEvent e)
+    {
+      // FIXME: This method calls JComboBox.selectWithKeyChar if the key that was 
+      // pressed is not a navigation key. 
+    }
+  }
+
+  /**
+   * This class handles to the changes occuring in the JComboBox's data model
+   */
+  public class ListDataHandler extends Object implements ListDataListener
+  {
+    /**
+     * Creates a new ListDataHandler object.
+     */
+    public ListDataHandler()
+    {
+    }
+
+    /**
+     * This method is invoked content's of JComboBox's data model  are changed
+     *
+     * @param e ListDataEvent describing the change.
+     */
+    public void contentsChanged(ListDataEvent e)
+    {
+      // if the item is selected or deselected
+    }
+
+    /**
+     * This method is invoked when items were added to the JComboBox's data
+     * model.
+     *
+     * @param e ListDataEvent describing the change.
+     */
+    public void intervalAdded(ListDataEvent e)
+    {
+      // must determine if the size of the combo box should change
+      int start = e.getIndex0();
+      int end = e.getIndex1();
+
+      ComboBoxModel model = comboBox.getModel();
+      ListCellRenderer renderer = comboBox.getRenderer();
+
+      if (largestItemSize == null)
+       largestItemSize = new Dimension(0, 0);
+
+      for (int i = start - 1; i < end; i++)
+        {
+         Object item = model.getElementAt(i);
+         Component comp = renderer.getListCellRendererComponent(new JList(),
+                                                                item, -1,
+                                                                false, false);
+         if (comp.getPreferredSize().getWidth() > largestItemSize.getWidth())
+           largestItemSize = comp.getPreferredSize();
+        }
+    }
+
+    /**
+     * This method is invoked when items were removed from the JComboBox's
+     * data model.
+     *
+     * @param e ListDataEvent describing the change.
+     */
+    public void intervalRemoved(ListDataEvent e)
+    {
+      // must determine if the size of the combo box should change
+      // FIXME: need to implement
+    }
+  }
+
+  /**
+   * This class handles PropertyChangeEvents fired by JComboBox.
+   */
+  public class PropertyChangeHandler extends Object
+    implements PropertyChangeListener
+  {
+    public PropertyChangeHandler()
+    {
+    }
+
+    public void propertyChange(PropertyChangeEvent e)
+    {
+      if (e.getPropertyName().equals(JComboBox.ENABLED_CHANGED_PROPERTY))
+        {
+         // disable arrow button       
+         arrowButton.setEnabled(comboBox.isEnabled());
+
+         if (comboBox.isEditable())
+           comboBox.getEditor().getEditorComponent().setEnabled(comboBox
+                                                                .isEnabled());
+        }
+      else if (e.getPropertyName().equals(JComboBox.EDITABLE_CHANGED_PROPERTY))
+        {
+         if (comboBox.isEditable())
+           {
+             configureEditor();
+             addEditor();
+           }
+         else
+           {
+             unconfigureEditor();
+             removeEditor();
+           }
+
+         comboBox.revalidate();
+         comboBox.repaint();
+        }
+
+      // FIXME: Need to handle changes in other bound properties.      
+    }
+  }
+
+  /**
+   * MouseHandler listens to mouse events occuring in the combo box. This
+   * class is responsible for repainting this JComboBox whenever the mouse is
+   * being pressed or released over it.
+   */
+  private class MouseHandler extends MouseAdapter
+  {
+    /**
+     * This method is invoked when mouse is pressed over the combo box. It
+     * repaints the combo box accordinglly
+     *
+     * @param e the MouseEvent
+     */
+    public void mousePressed(MouseEvent e)
+    {
+      if (comboBox.isEnabled())
+        {
+         if (e.getSource() instanceof JComboBox)
+           {
+             arrowButton.getModel().setPressed(true);
+             arrowButton.getModel().setArmed(true);
+           }
+
+         comboBox.repaint();
+
+         if (e.getSource() instanceof BasicArrowButton)
+           toggleOpenClose();
+        }
+    }
+
+    /**
+     * This method is invoked when mouse is released over the combo box. It
+     * repaints the combo box accordinglly
+     *
+     * @param e the MouseEvent
+     */
+    public void mouseReleased(MouseEvent e)
+    {
+      if (comboBox.isEnabled())
+        {
+         if (e.getSource() instanceof JComboBox)
+           {
+             arrowButton.getModel().setPressed(false);
+             arrowButton.getModel().setArmed(false);
+           }
+
+         comboBox.repaint();
+        }
+    }
+  }
+}
diff --git a/libjava/javax/swing/plaf/basic/BasicComboPopup.java b/libjava/javax/swing/plaf/basic/BasicComboPopup.java
new file mode 100644 (file)
index 0000000..61d2dfb
--- /dev/null
@@ -0,0 +1,933 @@
+/* BasicComboPopup.java --
+   Copyright (C) 2004  Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+package javax.swing.plaf.basic;
+
+import java.awt.Component;
+import java.awt.Dimension;
+import java.awt.Rectangle;
+import java.awt.event.ItemEvent;
+import java.awt.event.ItemListener;
+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.MouseMotionAdapter;
+import java.awt.event.MouseMotionListener;
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+import javax.swing.ComboBoxModel;
+import javax.swing.JComboBox;
+import javax.swing.JComponent;
+import javax.swing.JLabel;
+import javax.swing.JList;
+import javax.swing.JPopupMenu;
+import javax.swing.JScrollPane;
+import javax.swing.ListCellRenderer;
+import javax.swing.ListSelectionModel;
+import javax.swing.SwingConstants;
+import javax.swing.Timer;
+import javax.swing.event.ListDataEvent;
+import javax.swing.event.ListDataListener;
+import javax.swing.event.ListSelectionEvent;
+import javax.swing.event.ListSelectionListener;
+import javax.swing.event.PopupMenuEvent;
+import javax.swing.event.PopupMenuListener;
+
+
+/**
+ * UI Delegate for ComboPopup
+ *
+ * @author Olga Rodimina
+ */
+public class BasicComboPopup extends JPopupMenu implements ComboPopup
+{
+  protected Timer autoscrollTimer;
+
+  /**
+   * ComboBox associated with this popup
+   */
+  protected JComboBox comboBox;
+
+  /*
+   * FIXME: Document fields below
+   */
+  protected boolean hasEntered;
+  protected boolean isAutoScrolling;
+
+  /**
+   * ItemListener listening to the selection changes in the combo box
+   */
+  protected ItemListener itemListener;
+
+  /**
+   * This listener is not used
+   */
+  protected KeyListener keyListener;
+
+  /**
+   * JList which is used to display item is the combo box
+   */
+  protected JList list;
+
+  /**
+   * This listener is not used
+   */
+  protected ListDataListener listDataListener;
+
+  /**
+   * MouseListener listening to mouse events occuring in the  combo box's
+   * list.
+   */
+  protected MouseListener listMouseListener;
+
+  /**
+   * MouseMotionListener listening to mouse motion events occuring  in the
+   * combo box's list
+   */
+  protected MouseMotionListener listMouseMotionListener;
+
+  /**
+   * This listener is not used
+   */
+  protected ListSelectionListener listSelectionListener;
+
+  /**
+   * MouseListener listening to mouse events occuring in the combo box
+   */
+  protected MouseListener mouseListener;
+
+  /**
+   * MouseMotionListener listening to mouse motion events occuring in the
+   * combo box
+   */
+  protected MouseMotionListener mouseMotionListener;
+
+  /**
+   * PropertyChangeListener listening to changes occuring in the bound
+   * properties of the combo box
+   */
+  protected PropertyChangeListener propertyChangeListener;
+
+  /*
+   * FIXME: Document fields below
+   */
+  protected static int SCROLL_DOWN = 1;
+  protected static int SCROLL_UP = 0;
+  protected int scrollDirection;
+
+  /**
+   * JScrollPane that contains list portion of the combo box
+   */
+  protected JScrollPane scroller;
+
+  /**
+   * This field is not used
+   */
+  protected boolean valueIsAdjusting;
+
+  /**
+   * Creates a new BasicComboPopup object.
+   *
+   * @param comboBox the combo box with which this popup should be associated
+   */
+  public BasicComboPopup(JComboBox comboBox)
+  {
+    this.comboBox = comboBox;
+    installComboBoxListeners();
+
+    // initialize list that will be used to display elements of the combo box  
+    this.list = createList();
+    ((JLabel) list.getCellRenderer()).setHorizontalAlignment(SwingConstants.LEFT);
+    configureList();
+
+    // initialize scroller. Add list to the scroller.  
+    scroller = createScroller();
+    configureScroller();
+
+    // add scroller with list inside of it to JPopupMenu
+    super.add(scroller);
+
+    setLightWeightPopupEnabled(comboBox.isLightWeightPopupEnabled());
+  }
+
+  /**
+   * This method displays drow down list of combo box items on the screen.
+   */
+  public void show()
+  {
+    Rectangle cbBounds = comboBox.getBounds();
+
+    // popup should have same width as the comboBox and should be hight anough
+    // to display number of rows equal to 'maximumRowCount' property
+    int popupHeight = getPopupHeightForRowCount(comboBox.getMaximumRowCount())
+                      + 4;
+
+    super.setPopupSize(cbBounds.width, popupHeight);
+
+    // location specified is relative to comboBox
+    super.show(comboBox, 0, cbBounds.height);
+  }
+
+  /**
+   * This method hides drop down list of items
+   */
+  public void hide()
+  {
+    super.setVisible(false);
+  }
+
+  /**
+   * Return list cointaining JComboBox's items
+   *
+   * @return list cointaining JComboBox's items
+   */
+  public JList getList()
+  {
+    return list;
+  }
+
+  /**
+   * Returns MouseListener that is listening to mouse events occuring in the
+   * combo box.
+   *
+   * @return MouseListener
+   */
+  public MouseListener getMouseListener()
+  {
+    return mouseListener;
+  }
+
+  /**
+   * Returns MouseMotionListener that is listening to mouse  motion events
+   * occuring in the combo box.
+   *
+   * @return MouseMotionListener
+   */
+  public MouseMotionListener getMouseMotionListener()
+  {
+    return mouseMotionListener;
+  }
+
+  /**
+   * Returns KeyListener listening to key events occuring in the combo box.
+   * This method returns null because KeyHandler is not longer used.
+   *
+   * @return KeyListener
+   */
+  public KeyListener getKeyListener()
+  {
+    return keyListener;
+  }
+
+  /**
+   * This method uninstalls the UI for the  given JComponent.
+   */
+  public void uninstallingUI()
+  {
+    uninstallComboBoxModelListeners(comboBox.getModel());
+
+    uninstallListeners();
+    uninstallKeyboardActions();
+  }
+
+  /**
+   * This method uninstalls listeners that were listening to changes occuring
+   * in the comb box's data model
+   *
+   * @param model data model for the combo box from which to uninstall
+   *        listeners
+   */
+  protected void uninstallComboBoxModelListeners(ComboBoxModel model)
+  {
+    model.removeListDataListener(listDataListener);
+  }
+
+  /**
+   * This method uninstalls keyboard actions installed by the UI.
+   */
+  protected void uninstallKeyboardActions()
+  {
+    // FIXME: Need to implement
+  }
+
+  /**
+   * This method fires PopupMenuEvent indicating that combo box's popup list
+   * of items will become visible
+   */
+  protected void firePopupMenuWillBecomeVisible()
+  {
+    // FIXME: Need to implement
+  }
+
+  /**
+   * This method fires PopupMenuEvent indicating that combo box's popup list
+   * of items will become invisible.
+   */
+  protected void firePopupMenuWillBecomeInvisible()
+  {
+    // FIXME: Need to implement
+  }
+
+  /**
+   * This method fires PopupMenuEvent indicating that combo box's popup list
+   * of items was closed without selection.
+   */
+  protected void firePopupMenuCanceled()
+  {
+    // FIXME: Need to implement
+  }
+
+  /**
+   * Creates MouseListener to listen to mouse events occuring in the combo
+   * box. Note that this listener doesn't listen to mouse events occuring in
+   * the popup portion of the combo box, it only listens to main combo box
+   * part.
+   *
+   * @return new MouseMotionListener that listens to mouse events occuring in
+   *         the combo box
+   */
+  protected MouseListener createMouseListener()
+  {
+    return new InvocationMouseHandler();
+  }
+
+  /**
+   * Create Mouse listener that listens to mouse dragging events occuring in
+   * the combo box. This listener is responsible for changing the selection
+   * in the combo box list to the component over which mouse is being
+   * currently dragged
+   *
+   * @return new MouseMotionListener that listens to mouse dragging events
+   *         occuring in the combo box
+   */
+  protected MouseMotionListener createMouseMotionListener()
+  {
+    return new InvocationMouseMotionHandler();
+  }
+
+  /**
+   * KeyListener created in this method is not used anymore.
+   *
+   * @return KeyListener that does nothing
+   */
+  protected KeyListener createKeyListener()
+  {
+    return new InvocationKeyHandler();
+  }
+
+  /**
+   * ListSelectionListener created in this method is not used anymore
+   *
+   * @return ListSelectionListener that does nothing
+   */
+  protected ListSelectionListener createListSelectionListener()
+  {
+    return new ListSelectionHandler();
+  }
+
+  /**
+   * Creates ListDataListener. This method returns null, because
+   * ListDataHandler class is obsolete and is no longer used.
+   *
+   * @return null
+   */
+  protected ListDataListener createListDataListener()
+  {
+    return null;
+  }
+
+  /**
+   * This method creates ListMouseListener to listen to mouse events occuring
+   * in the combo box's item list.
+   *
+   * @return MouseListener to listen to mouse events occuring in the combo
+   *         box's items list.
+   */
+  protected MouseListener createListMouseListener()
+  {
+    return new ListMouseHandler();
+  }
+
+  /**
+   * Creates ListMouseMotionlistener to listen to mouse motion events occuring
+   * in the combo box's list. This listener is responsible for highlighting
+   * items in the list when mouse is moved over them.
+   *
+   * @return MouseMotionListener that handles mouse motion events occuring in
+   *         the list of the combo box.
+   */
+  protected MouseMotionListener createListMouseMotionListener()
+  {
+    return new ListMouseMotionHandler();
+  }
+
+  /**
+   * Creates PropertyChangeListener to handle changes in the JComboBox's bound
+   * properties.
+   *
+   * @return PropertyChangeListener to handle changes in the JComboBox's bound
+   *         properties.
+   */
+  protected PropertyChangeListener createPropertyChangeListener()
+  {
+    return new PropertyChangeHandler();
+  }
+
+  /**
+   * Creates new ItemListener that will listen to ItemEvents occuring in the
+   * combo box.
+   *
+   * @return ItemListener to listen to ItemEvents occuring in the combo box.
+   */
+  protected ItemListener createItemListener()
+  {
+    return new ItemHandler();
+  }
+
+  /**
+   * Creates JList that will be used to display items in the combo box.
+   *
+   * @return JList that will be used to display items in the combo box.
+   */
+  protected JList createList()
+  {
+    JList l = new JList(comboBox.getModel());
+    l.setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION);
+    return l;
+  }
+
+  /**
+   * This method configures the list of comboBox's items by setting  default
+   * properties and installing listeners.
+   */
+  protected void configureList()
+  {
+    list.setModel(comboBox.getModel());
+
+    if (comboBox.getItemCount() < comboBox.getMaximumRowCount())
+      list.setVisibleRowCount(comboBox.getItemCount());
+    else
+      list.setVisibleRowCount(comboBox.getMaximumRowCount());
+    installListListeners();
+  }
+
+  /**
+   * This method installs list listeners.
+   */
+  protected void installListListeners()
+  {
+    // mouse listener listening to mouse events occuring in the 
+    // combo box's list of items.
+    listMouseListener = createListMouseListener();
+    list.addMouseListener(listMouseListener);
+
+    // mouse listener listening to mouse motion events occuring in the
+    // combo box's list of items
+    listMouseMotionListener = createListMouseMotionListener();
+    list.addMouseMotionListener(listMouseMotionListener);
+
+    listSelectionListener = createListSelectionListener();
+    list.addListSelectionListener(listSelectionListener);
+  }
+
+  /**
+   * This method creates scroll pane that will contain the list of comboBox's
+   * items inside of it.
+   *
+   * @return JScrollPane
+   */
+  protected JScrollPane createScroller()
+  {
+    return new JScrollPane();
+  }
+
+  /**
+   * This method configures scroll pane to contain list of comboBox's  items
+   */
+  protected void configureScroller()
+  {
+    scroller.getViewport().setView(list);
+    scroller.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
+  }
+
+  /**
+   * This method configures popup menu that will be used to display Scrollpane
+   * with list of items inside of it.
+   */
+  protected void configurePopup()
+  {
+    // FIXME: Need to implement
+  }
+
+  /*
+   * This method installs listeners that will listen to changes occuring
+   * in the combo box.
+   */
+  protected void installComboBoxListeners()
+  {
+    // mouse listener that listens to mouse event in combo box
+    mouseListener = createMouseListener();
+    comboBox.addMouseListener(mouseListener);
+
+    // mouse listener that listens to mouse dragging events in the combo box
+    mouseMotionListener = createMouseMotionListener();
+    comboBox.addMouseMotionListener(mouseMotionListener);
+
+    // item listener listenening to selection events in the combo box
+    itemListener = createItemListener();
+    comboBox.addItemListener(itemListener);
+
+    propertyChangeListener = createPropertyChangeListener();
+    comboBox.addPropertyChangeListener(propertyChangeListener);
+  }
+
+  /**
+   * This method installs listeners that will listen to changes occuring in
+   * the comb box's data model
+   *
+   * @param model data model for the combo box for which to install listeners
+   */
+  protected void installComboBoxModelListeners(ComboBoxModel model)
+  {
+    // list data listener to listen for ListDataEvents in combo box.
+    // This listener is now obsolete and nothing is done here
+    listDataListener = createListDataListener();
+    comboBox.getModel().addListDataListener(listDataListener);
+  }
+
+  /**
+   * DOCUMENT ME!
+   */
+  protected void installKeyboardActions()
+  {
+    // FIXME: Need to implement
+  }
+
+  /**
+   * This method always returns false to indicate that  items in the combo box
+   * list are not focus traversable.
+   *
+   * @return false
+   */
+  public boolean isFocusTraversable()
+  {
+    return false;
+  }
+
+  /**
+   * DOCUMENT ME!
+   *
+   * @param direction DOCUMENT ME!
+   */
+  protected void startAutoScrolling(int direction)
+  {
+    // FIXME: Need to implement
+  }
+
+  /**
+   * DOCUMENT ME!
+   */
+  protected void stopAutoScrolling()
+  {
+    // FIXME: Need to implement
+  }
+
+  /**
+   * DOCUMENT ME!
+   */
+  protected void autoScrollUp()
+  {
+    // FIXME: Need to implement
+  }
+
+  /**
+   * DOCUMENT ME!
+   */
+  protected void autoScrollDown()
+  {
+    // FIXME: Need to implement
+  }
+
+  /**
+   * This method helps to delegate focus to the right component in the
+   * JComboBox. If the comboBox is editable then focus is sent to
+   * ComboBoxEditor, otherwise it is delegated to JComboBox.
+   *
+   * @param e MouseEvent
+   */
+  protected void delegateFocus(MouseEvent e)
+  {
+    // FIXME: Need to implement
+  }
+
+  /**
+   * This method displays combo box popup if the popup is  not currently shown
+   * on the screen and hides it if it is  currently visible
+   */
+  protected void togglePopup()
+  {
+    if (BasicComboPopup.this.isVisible())
+      hide();
+    else
+      show();
+  }
+
+  /**
+   * DOCUMENT ME!
+   *
+   * @param e DOCUMENT ME!
+   *
+   * @return DOCUMENT ME!
+   */
+  protected MouseEvent convertMouseEvent(MouseEvent e)
+  {
+    return null;
+  }
+
+  /**
+   * Returns required height of the popup such that number of items visible in
+   * it are equal to the maximum row count.  By default
+   * comboBox.maximumRowCount=8
+   *
+   * @param maxRowCount number of maximum visible rows in the  combo box's
+   *        popup list of items
+   *
+   * @return height of the popup required to fit number of items  equal to
+   *         JComboBox.maximumRowCount.
+   */
+  protected int getPopupHeightForRowCount(int maxRowCount)
+  {
+    int totalHeight = 0;
+    ListCellRenderer rend = list.getCellRenderer();
+
+    if (comboBox.getItemCount() < maxRowCount)
+      maxRowCount = comboBox.getItemCount();
+
+    for (int i = 0; i < maxRowCount; i++)
+      {
+       Component comp = rend.getListCellRendererComponent(list,
+                                                          list.getModel()
+                                                              .getElementAt(i),
+                                                          -1, false, false);
+       Dimension dim = comp.getPreferredSize();
+       totalHeight += dim.height;
+      }
+
+    return totalHeight;
+  }
+
+  /**
+   * DOCUMENT ME!
+   *
+   * @param px DOCUMENT ME!
+   * @param py DOCUMENT ME!
+   * @param pw DOCUMENT ME!
+   * @param ph DOCUMENT ME!
+   *
+   * @return DOCUMENT ME!
+   */
+  protected Rectangle computePopupBounds(int px, int py, int pw, int ph)
+  {
+    return new Rectangle(px, py, pw, ph);
+  }
+
+  /**
+   * This method changes the selection in the list to the item over which  the
+   * mouse is currently located.
+   *
+   * @param anEvent MouseEvent
+   * @param shouldScroll DOCUMENT ME!
+   */
+  protected void updateListBoxSelectionForEvent(MouseEvent anEvent,
+                                                boolean shouldScroll)
+  {
+    // FIXME: Need to implement
+  }
+
+  /**
+   * InvocationMouseHandler is a listener that listens to mouse events
+   * occuring in the combo box. Note that this listener doesn't listen to
+   * mouse events occuring in the popup portion of the combo box, it only
+   * listens to main combo box part(area that displays selected item).  This
+   * listener is responsible for showing and hiding popup portion  of the
+   * combo box.
+   */
+  protected class InvocationMouseHandler extends MouseAdapter
+  {
+    /**
+     * Creates a new InvocationMouseHandler object.
+     */
+    protected InvocationMouseHandler()
+    {
+    }
+
+    /**
+     * This method is invoked whenever mouse is being pressed over the main
+     * part of the combo box. This method will show popup if  the popup is
+     * not shown on the screen right now, and it will hide popup otherwise.
+     *
+     * @param e MouseEvent that should be handled
+     */
+    public void mousePressed(MouseEvent e)
+    {
+      if (comboBox.isEnabled())
+       togglePopup();
+    }
+
+    /**
+     * This method is invoked whenever mouse is released
+     *
+     * @param e MouseEvent that should be handled
+     */
+    public void mouseReleased(MouseEvent e)
+    {
+      // FIXME: should handle dragging events here, if
+      // mouse was dragged and released over the list of combobox's items,
+      // then item over which it was released should be selected.
+    }
+  }
+
+  /**
+   * InvocationMouseMotionListener is a mouse listener that listens to mouse
+   * dragging events occuring in the combo box.
+   */
+  protected class InvocationMouseMotionHandler extends MouseMotionAdapter
+  {
+    /**
+     * Creates a new InvocationMouseMotionHandler object.
+     */
+    protected InvocationMouseMotionHandler()
+    {
+    }
+
+    public void mouseDragged(MouseEvent e)
+    {
+    }
+  }
+
+  /**
+   * ItemHandler is an item listener that listens to selection event occuring
+   * in the combo box. FIXME: should specify here what it does when item is
+   * selected or deselected in the combo box list.
+   */
+  protected class ItemHandler extends Object implements ItemListener
+  {
+    /**
+     * Creates a new ItemHandler object.
+     */
+    protected ItemHandler()
+    {
+    }
+
+    /**
+     * This method responds to the selection events occuring in the combo box.
+     *
+     * @param e ItemEvent specifying the combo box's selection
+     */
+    public void itemStateChanged(ItemEvent e)
+    {
+    }
+  }
+
+  /**
+   * ListMouseHandler is a listener that listens to mouse events occuring in
+   * the combo box's list of items. This class is responsible for hiding
+   * popup portion of the combo box if the mouse is released inside the combo
+   * box's list.
+   */
+  protected class ListMouseHandler extends MouseAdapter
+  {
+    protected ListMouseHandler()
+    {
+    }
+
+    public void mousePressed(MouseEvent e)
+    {
+    }
+
+    public void mouseReleased(MouseEvent anEvent)
+    {
+      int index = list.locationToIndex(anEvent.getPoint());
+      comboBox.setSelectedIndex(index);
+      hide();
+    }
+  }
+
+  /**
+   * ListMouseMotionHandler listens to mouse motion events occuring in the
+   * combo box's list. This class is responsible for highlighting items in
+   * the list when mouse is moved over them
+   */
+  protected class ListMouseMotionHandler extends MouseMotionAdapter
+  {
+    protected ListMouseMotionHandler()
+    {
+    }
+
+    public void mouseMoved(MouseEvent anEvent)
+    {
+      // FIXME: Need to implement
+      // NOTE: the change isn't reflected in data model of the combo box.
+      // The items are only highlited, but not selected
+    }
+  }
+
+  /**
+   * This class listens to changes occuring in the bound properties of the
+   * combo box
+   */
+  protected class PropertyChangeHandler extends Object
+    implements PropertyChangeListener
+  {
+    protected PropertyChangeHandler()
+    {
+    }
+
+    public void propertyChange(PropertyChangeEvent e)
+    {
+      if (e.getPropertyName().equals(JComboBox.RENDERER_CHANGED_PROPERTY))
+        {
+         list.setCellRenderer((ListCellRenderer) e.getNewValue());
+         revalidate();
+         repaint();
+        }
+    }
+  }
+
+  // ------ private helper methods --------------------
+
+  /**
+   * This method uninstalls listeners installed by the UI
+   */
+  private void uninstallListeners()
+  {
+    uninstallListListeners();
+    uninstallComboBoxListeners();
+    uninstallComboBoxModelListeners(comboBox.getModel());
+  }
+
+  /**
+   * This method uninstalls Listeners registered with combo boxes list of
+   * items
+   */
+  private void uninstallListListeners()
+  {
+    list.removeMouseListener(listMouseListener);
+    listMouseListener = null;
+
+    list.removeMouseMotionListener(listMouseMotionListener);
+    listMouseMotionListener = null;
+  }
+
+  /**
+   * This method uninstalls listeners listening to combo box  associated with
+   * this popup menu
+   */
+  private void uninstallComboBoxListeners()
+  {
+    comboBox.removeMouseListener(mouseListener);
+    mouseListener = null;
+
+    comboBox.removeMouseMotionListener(mouseMotionListener);
+    mouseMotionListener = null;
+
+    comboBox.removeItemListener(itemListener);
+    itemListener = null;
+
+    comboBox.removePropertyChangeListener(propertyChangeListener);
+    propertyChangeListener = null;
+  }
+
+  // --------------------------------------------------------------------
+  //  The following classes are here only for backwards API compatibility
+  //  They aren't used.
+  // --------------------------------------------------------------------
+
+  /**
+   * This class is not used any more.
+   */
+  public class ListDataHandler extends Object implements ListDataListener
+  {
+    public ListDataHandler()
+    {
+    }
+
+    public void contentsChanged(ListDataEvent e)
+    {
+    }
+
+    public void intervalAdded(ListDataEvent e)
+    {
+    }
+
+    public void intervalRemoved(ListDataEvent e)
+    {
+    }
+  }
+
+  /**
+   * This class is not used anymore
+   */
+  protected class ListSelectionHandler extends Object
+    implements ListSelectionListener
+  {
+    protected ListSelectionHandler()
+    {
+    }
+
+    public void valueChanged(ListSelectionEvent e)
+    {
+    }
+  }
+
+  /**
+   * This class is not used anymore
+   */
+  public class InvocationKeyHandler extends KeyAdapter
+  {
+    public InvocationKeyHandler()
+    {
+    }
+
+    public void keyReleased(KeyEvent e)
+    {
+    }
+  }
+}
diff --git a/libjava/javax/swing/plaf/basic/BasicFormattedTextFieldUI.java b/libjava/javax/swing/plaf/basic/BasicFormattedTextFieldUI.java
new file mode 100644 (file)
index 0000000..c61dc40
--- /dev/null
@@ -0,0 +1,62 @@
+/* BasicFormattedTextFieldUI.java
+   Copyright (C) 2004  Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package javax.swing.plaf.basic;
+
+import javax.swing.JComponent;
+import javax.swing.plaf.ComponentUI;
+
+/**
+ * @since 1.4
+ */
+public class BasicFormattedTextFieldUI extends BasicTextFieldUI
+{
+  public BasicFormattedTextFieldUI()
+  {
+  }
+
+  public static ComponentUI createUI(JComponent c)
+  {
+    return new BasicFormattedTextFieldUI();
+  }
+
+  protected String getPropertyPrefix()
+  {
+    return "FormattedTextField";
+  }
+}
\ No newline at end of file
diff --git a/libjava/javax/swing/plaf/basic/BasicPasswordFieldUI.java b/libjava/javax/swing/plaf/basic/BasicPasswordFieldUI.java
new file mode 100644 (file)
index 0000000..fe1c490
--- /dev/null
@@ -0,0 +1,61 @@
+/* BasicPasswordFieldUI.java
+   Copyright (C) 2004  Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package javax.swing.plaf.basic;
+
+import javax.swing.JComponent;
+import javax.swing.plaf.ComponentUI;
+import javax.swing.text.Element;
+import javax.swing.text.View;
+
+public class BasicPasswordFieldUI extends BasicTextFieldUI
+{
+  public BasicPasswordFieldUI()
+  {
+  }
+
+  public static ComponentUI createUI(JComponent c)
+  {
+    return new BasicPasswordFieldUI();
+  }
+
+  protected String getPropertyPrefix()
+  {
+    return "PasswordField";
+  }
+}
diff --git a/libjava/javax/swing/plaf/basic/BasicSpinnerUI.java b/libjava/javax/swing/plaf/basic/BasicSpinnerUI.java
new file mode 100644 (file)
index 0000000..0f5e761
--- /dev/null
@@ -0,0 +1,572 @@
+/* SpinnerUI.java --
+   Copyright (C) 2003 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+package javax.swing.plaf.basic;
+
+import java.awt.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.Timer;
+import javax.swing.UIDefaults;
+import javax.swing.UIManager;
+import javax.swing.plaf.ComponentUI;
+import javax.swing.plaf.SpinnerUI;
+
+
+/**
+ * DOCUMENT ME!
+ *
+ * @author Ka-Hing Cheung
+ *
+ * @see javax.swing.JSpinner
+ * @since 1.4
+ */
+public class BasicSpinnerUI extends SpinnerUI
+{
+  /**
+   * Creates a new <code>ComponentUI</code> for the specified
+   * <code>JComponent</code>
+   *
+   * @param c DOCUMENT ME!
+   *
+   * @return a ComponentUI
+   */
+  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 evt)
+       {
+         // FIXME: Add check for enabled property change. Need to
+         // disable the buttons.
+         if ("editor".equals(evt.getPropertyName()))
+           BasicSpinnerUI.this.replaceEditor((JComponent) evt.getOldValue(),
+                                             (JComponent) evt.getNewValue());
+       }
+      };
+  }
+
+  /**
+   * 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()
+  {
+    /* most of it copied from BasicLabelUI, I don't know what keys are
+       available, so someone may want to update this. Hence: TODO
+    */
+    UIDefaults defaults = UIManager.getLookAndFeelDefaults();
+    /*
+    spinner.setForeground(defaults.getColor("Spinner.foreground"));
+    spinner.setBackground(defaults.getColor("Spinner.background"));
+    spinner.setFont(defaults.getFont("Spinner.font"));
+    spinner.setBorder(defaults.getBorder("Spinner.border"));
+    */
+    spinner.setLayout(createLayout());
+  }
+
+  /*
+   * 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 = false;
+         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 = false;
+         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();
+
+  /**
+   * DOCUMENT ME!
+   */
+  private class DefaultLayoutManager implements LayoutManager
+  {
+    /**
+     * DOCUMENT ME!
+     *
+     * @param parent DOCUMENT ME!
+     */
+    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 = minSize(editor);
+         Dimension n = minSize(next);
+         Dimension p = minSize(previous);
+         Dimension s = spinner.getPreferredSize();
+
+         int x = l2r ? i.left : i.right;
+         int y = i.top;
+         int w = Math.max(p.width, n.width);
+         int h = Math.max(p.height, n.height);
+         h = Math.max(h, e.height / 2);
+         int e_width = s.width - w;
+
+         if (l2r)
+           {
+             setBounds(editor, x, y + (s.height - e.height) / 2, e_width,
+                       e.height);
+             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, w, h);
+             x += w;
+             y -= h;
+
+             setBounds(editor, x, y, e_width, e.height);
+           }
+        }
+    }
+
+    /**
+     * DOCUMENT ME!
+     *
+     * @param parent DOCUMENT ME!
+     *
+     * @return DOCUMENT ME!
+     */
+    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;
+      int otherHeight = 0;
+
+      if (next != null)
+        {
+         Dimension tmp = next.getMinimumSize();
+         nextWidth = tmp.width;
+         otherHeight += tmp.height;
+        }
+      if (previous != null)
+        {
+         Dimension tmp = previous.getMinimumSize();
+         previousWidth = tmp.width;
+         otherHeight += tmp.height;
+        }
+
+      d.height = Math.max(d.height, otherHeight);
+      d.width += Math.max(nextWidth, previousWidth);
+
+      return d;
+    }
+
+    /**
+     * DOCUMENT ME!
+     *
+     * @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;
+      int otherHeight = 0;
+
+      if (next != null)
+        {
+         Dimension tmp = next.getPreferredSize();
+         nextWidth = tmp.width;
+         otherHeight += tmp.height;
+        }
+      if (previous != null)
+        {
+         Dimension tmp = previous.getPreferredSize();
+         previousWidth = tmp.width;
+         otherHeight += tmp.height;
+        }
+
+      d.height = Math.max(d.height, otherHeight);
+      d.width += Math.max(nextWidth, previousWidth);
+
+      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 minSize(Component c)
+    {
+      if (c == null)
+       return new Dimension();
+      else
+       return c.getMinimumSize();
+    }
+
+    /**
+     * DOCUMENT ME!
+     *
+     * @param c DOCUMENT ME!
+     * @param x DOCUMENT ME!
+     * @param y DOCUMENT ME!
+     * @param w DOCUMENT ME!
+     * @param h DOCUMENT ME!
+     */
+    private void setBounds(Component c, int x, int y, int w, int h)
+    {
+      if (c != null)
+       c.setBounds(x, y, w, h);
+    }
+
+    /** DOCUMENT ME! */
+    private Component editor;
+
+    /** DOCUMENT ME! */
+    private Component next;
+
+    /** DOCUMENT ME! */
+    private Component previous;
+  }
+}
diff --git a/libjava/javax/swing/plaf/basic/BasicTableHeaderUI.java b/libjava/javax/swing/plaf/basic/BasicTableHeaderUI.java
new file mode 100644 (file)
index 0000000..c55c940
--- /dev/null
@@ -0,0 +1,301 @@
+/* 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., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+package javax.swing.plaf.basic;
+
+import java.awt.Component;
+import java.awt.Dimension;
+import java.awt.Graphics;
+import java.awt.Rectangle;
+import java.awt.event.MouseEvent;
+import javax.swing.CellRendererPane;
+import javax.swing.JComponent;
+import javax.swing.UIDefaults;
+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;
+
+
+public class BasicTableHeaderUI
+  extends TableHeaderUI
+{
+
+  public static ComponentUI createUI(JComponent h)
+  {
+    return new BasicTableHeaderUI();
+  }
+
+  protected JTableHeader header;
+  protected MouseInputListener mouseInputListener;
+  protected CellRendererPane rendererPane;
+  protected Border cellBorder;
+
+  class MouseInputHandler
+    implements MouseInputListener
+  {
+    public void mouseClicked(MouseEvent e) {}
+    public void mouseDragged(MouseEvent e) {}
+    public void mouseEntered(MouseEvent e) {}
+    public void mouseExited(MouseEvent e) {}
+    public void mouseMoved(MouseEvent e) {}
+    public void mousePressed(MouseEvent e) {}
+    public void mouseReleased(MouseEvent e) {}
+  }
+
+  protected MouseInputListener createMouseInputListener()
+  {
+    return new MouseInputHandler();
+  }
+
+  public BasicTableHeaderUI()
+  {
+    mouseInputListener = createMouseInputListener();
+  }
+
+  protected void installDefaults()
+  {
+    UIDefaults defaults = UIManager.getLookAndFeelDefaults();
+    header.setBackground(defaults.getColor("TableHeader.background"));
+    header.setForeground(defaults.getColor("TableHeader.foreground"));
+    header.setFont(defaults.getFont("TableHeader.font"));
+    cellBorder = defaults.getBorder("TableHeader.cellBorder");
+  }
+
+  protected void installKeyboardActions()
+  {
+  }
+
+  protected void installListeners()
+  {
+    header.addMouseListener(mouseInputListener);
+  }
+
+  public void installUI(JComponent c)
+  {
+    header = (JTableHeader) c;
+    installDefaults();
+    installKeyboardActions();
+    installListeners();
+  }
+
+  protected void uninstallDefaults()
+  {
+    header.setBackground(null);
+    header.setForeground(null);
+    header.setFont(null);
+  }
+
+  protected void uninstallKeyboardActions()
+  {
+  }
+
+  protected void uninstallListeners()
+  {
+    header.removeMouseListener(mouseInputListener);
+  }
+
+  public void uninstallUI(JComponent c)
+  {
+    uninstallListeners();
+    uninstallKeyboardActions();
+    uninstallDefaults();
+  }
+
+  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))
+          {
+            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);
+            gfx.translate(bounds.x, bounds.y);
+            comp.setSize(bounds.width, bounds.height);
+            comp.setLocation(0,0);
+            comp.paint(gfx);
+            gfx.translate(-bounds.x, -bounds.y);
+          }
+      }
+
+  }
+
+  public Dimension getMaximumSize(JComponent c)
+  {
+    TableColumnModel cmod = header.getColumnModel();
+    TableCellRenderer defaultRend = header.getDefaultRenderer();
+    int ncols = cmod.getColumnCount();    
+    int spacing = 0;
+    Dimension ret = getPreferredSize(c);
+    
+    if (header.getTable() != null 
+        && header.getTable().getInterCellSpacing() != null)
+      spacing = header.getTable().getInterCellSpacing().width;
+
+    ret.width = 0;
+    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.getMaximumSize();
+        ret.width += col.getMaxWidth();
+        ret.height = Math.max(ret.height, d.height);
+        ret.width += spacing;
+      }
+    return ret;
+  }
+
+  public Dimension getMinimumSize(JComponent c)
+  {
+    TableColumnModel cmod = header.getColumnModel();
+    TableCellRenderer defaultRend = header.getDefaultRenderer();
+    int ncols = cmod.getColumnCount();    
+    int spacing = 0;
+    Dimension ret = getPreferredSize(c);
+
+    if (header.getTable() != null 
+        && header.getTable().getInterCellSpacing() != null)
+      spacing = header.getTable().getInterCellSpacing().width;
+
+    ret.width = 0;
+    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.getMinimumSize();
+        ret.width += col.getMinWidth();
+        ret.width += spacing;
+        ret.height = Math.max(ret.height, d.height);
+      }
+    return ret;
+  }
+  
+  public Dimension getPreferredSize(JComponent c)
+  {
+    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 += d.width;
+        ret.width += spacing;
+        ret.height = Math.max(d.height, ret.height);        
+      }
+    return ret;
+  }
+  
+  
+}
diff --git a/libjava/javax/swing/plaf/basic/BasicTableUI.java b/libjava/javax/swing/plaf/basic/BasicTableUI.java
new file mode 100644 (file)
index 0000000..5fa8fb7
--- /dev/null
@@ -0,0 +1,374 @@
+/* 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., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+package javax.swing.plaf.basic;
+
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Dimension;
+import java.awt.Graphics;
+import java.awt.Point;
+import java.awt.Rectangle;
+import java.awt.event.KeyEvent;
+import java.awt.event.KeyListener;
+import java.awt.event.FocusEvent;
+import java.awt.event.FocusListener;
+import java.awt.event.MouseEvent;
+import javax.swing.CellRendererPane;
+import javax.swing.JComponent;
+import javax.swing.JTable;
+import javax.swing.ListSelectionModel;
+import javax.swing.event.MouseInputListener;
+import javax.swing.plaf.ComponentUI;
+import javax.swing.plaf.TableUI;
+import javax.swing.table.TableCellRenderer;
+import javax.swing.table.TableColumn;
+import javax.swing.table.TableColumnModel;
+import javax.swing.UIDefaults;
+import javax.swing.UIManager;
+
+
+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;
+
+  class FocusHandler implements FocusListener
+  {
+    public void focusGained(FocusEvent e) 
+    {
+    }
+    public void focusLost(FocusEvent e) 
+    {
+    }
+  }
+
+  class KeyHandler implements KeyListener
+  {
+    public void keyPressed(KeyEvent e) 
+    {
+    }
+    public void keyReleased(KeyEvent e) 
+    {
+    }
+    public void keyTyped(KeyEvent e) 
+    {
+    }
+  }
+
+  class MouseInputHandler implements MouseInputListener
+  {
+    Point begin, curr;
+
+    private int getRowForPoint(Point p)
+    {      
+      int y0 = table.getLocation().y;
+      int nrows = table.getRowCount();
+      Dimension gap = table.getInterCellSpacing();
+      int height = table.getRowHeight() + (gap == null ? 0 : gap.height);
+      int y = p.y;
+      for (int i = 0; i < nrows; ++i)
+        {
+          if (0 <= y && y < height)
+            return i;
+          y -= height;
+        }
+      return -1;
+    }
+
+    private int getColForPoint(Point p)
+    {
+      int x0 = table.getLocation().x;
+      int ncols = table.getColumnCount();
+      Dimension gap = table.getInterCellSpacing();
+      TableColumnModel cols = table.getColumnModel();      
+      int x = p.x;
+      for (int i = 0; i < ncols; ++i)
+        {
+          int width = cols.getColumn(i).getWidth() + (gap == null ? 0 : gap.width);
+          if (0 <= x && x < width)
+            return i;
+          x -= width;
+        }
+      return -1;
+    }
+
+    private void updateSelection()
+    {
+      if (table.getRowSelectionAllowed())
+        {
+          int lo_row = getRowForPoint(begin);
+          int hi_row  = getRowForPoint(curr);
+          ListSelectionModel rowModel = table.getSelectionModel();
+          if (lo_row != -1 && hi_row != -1)
+            rowModel.setSelectionInterval(lo_row, hi_row);
+        }
+
+      if (table.getColumnSelectionAllowed())
+        {
+          int lo_col = getColForPoint(begin);
+          int hi_col = getColForPoint(curr);
+          ListSelectionModel colModel = table.getColumnModel().getSelectionModel();
+          if (lo_col != -1 && hi_col != -1)
+            colModel.setSelectionInterval(lo_col, hi_col);
+        }
+    }
+
+    public void mouseClicked(MouseEvent e) 
+    {
+    }
+    public void mouseDragged(MouseEvent e) 
+    {
+      curr = new Point(e.getX(), e.getY());
+      updateSelection();      
+    }
+    public void mouseEntered(MouseEvent e) 
+    {
+    }
+    public void mouseExited(MouseEvent e) 
+    {
+    }
+    public void mouseMoved(MouseEvent e) 
+    {
+    }
+    public void mousePressed(MouseEvent e) 
+    {
+      begin = new Point(e.getX(), e.getY());
+      curr = new Point(e.getX(), e.getY());
+      updateSelection();
+    }
+    public void mouseReleased(MouseEvent e) 
+    {
+      begin = null;
+      curr = null;
+    }
+  }
+
+  protected FocusListener createFocusListener() 
+  {
+    return new FocusHandler();
+  }
+  protected KeyListener createKeyListener() 
+  {
+    return new KeyHandler();
+  }
+  protected MouseInputListener createMouseInputListener() 
+  {
+    return new MouseInputHandler();
+  }
+
+  public Dimension getMaximumSize(JComponent comp) 
+  {
+    return getPreferredSize(comp);
+  }
+
+  public Dimension getMinimumSize(JComponent comp) 
+  {
+    return getPreferredSize(comp);
+  }
+
+  public Dimension getPreferredSize(JComponent comp) 
+  {
+    int width = table.getColumnModel().getTotalColumnWidth();
+    int height = table.getRowCount() * table.getRowHeight();
+    return new Dimension(width, height);
+  }
+
+  protected void installDefaults() 
+  {
+    UIDefaults defaults = UIManager.getLookAndFeelDefaults();
+    table.setFont(defaults.getFont("Table.font"));
+    table.setGridColor(defaults.getColor("Table.gridColor"));
+    table.setForeground(defaults.getColor("Table.foreground"));
+    table.setBackground(defaults.getColor("Table.background"));
+    table.setSelectionForeground(defaults.getColor("Table.selectionForeground"));
+    table.setSelectionBackground(defaults.getColor("Table.selectionBackground"));
+    table.setOpaque(true);
+  }
+  protected void installKeyboardActions() 
+  {
+  }
+
+  protected void installListeners() 
+  {
+    table.addFocusListener(focusListener);  
+    table.addKeyListener(keyListener);
+    table.addMouseListener(mouseInputListener);    
+  }
+
+  protected void uninstallDefaults() 
+  {
+    table.setFont(null);
+    table.setGridColor(null);
+    table.setForeground(null);
+    table.setBackground(null);
+    table.setSelectionForeground(null);
+    table.setSelectionBackground(null);
+  }
+
+  protected void uninstallKeyboardActions() 
+  {
+  }
+
+  protected void uninstallListeners() 
+  {
+    table.removeFocusListener(focusListener);  
+    table.removeKeyListener(keyListener);
+    table.removeMouseListener(mouseInputListener);    
+  }
+
+  public void installUI(JComponent comp) 
+  {
+    table = (JTable)comp;
+    focusListener = createFocusListener();  
+    keyListener = createKeyListener();
+    mouseInputListener = createMouseInputListener();
+    installDefaults();
+    installKeyboardActions();
+    installListeners();
+  }
+
+  public void uninstallUI(JComponent c) 
+  {
+    uninstallListeners();
+    uninstallKeyboardActions();
+    uninstallDefaults();    
+  }
+
+  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();
+    TableColumnModel cols = table.getColumnModel();
+
+    int height = table.getRowHeight();
+    int x0 = 0, y0 = 0;
+    int x = x0;
+    int y = y0;
+
+    Dimension gap = table.getInterCellSpacing();
+    int ymax = clip.y + clip.height;
+    int xmax = clip.x + clip.width;
+
+    // paint the cell contents
+    for (int c = 0; c < ncols && x < xmax; ++c)
+      {
+        y = y0;
+        TableColumn col = cols.getColumn(c);
+        int width = col.getWidth();
+        int modelCol = col.getModelIndex();
+
+        for (int r = 0; r < nrows && y < ymax; ++r)
+          {
+            Rectangle bounds = new Rectangle(x, y, width, height);
+              if (bounds.intersects(clip))
+              {
+                TableCellRenderer rend = table.getCellRenderer(r, c);
+                Component comp = table.prepareRenderer(rend, r, c);
+                gfx.translate(x, y);
+                comp.setBounds(new Rectangle(0, 0, width, height));
+                comp.paint(gfx);
+                gfx.translate(-x, -y);
+              }
+              y += height;
+              if (gap != null)
+                y += gap.height;
+          }
+        x += width;
+        if (gap != null)
+          x += gap.width;
+      }
+
+    // tighten up the x and y max bounds
+    ymax = y;
+    xmax = x;
+
+    Color grid = table.getGridColor();    
+
+    // paint vertical grid lines    
+    if (grid != null && table.getShowVerticalLines())
+      {    
+        x = x0;
+        Color save = gfx.getColor();
+        gfx.setColor(grid);
+        boolean paintedLine = false;
+        for (int c = 0; c < ncols && x < xmax; ++c)
+          {
+            x += cols.getColumn(c).getWidth();;
+            if (gap != null)
+              x += gap.width;
+            gfx.drawLine(x, y0, x, ymax);
+            paintedLine = true;
+          }
+        gfx.setColor(save);
+      }
+
+    // paint horizontal grid lines    
+    if (grid != null && table.getShowHorizontalLines())
+      {    
+        y = y0;
+        Color save = gfx.getColor();
+        gfx.setColor(grid);
+        boolean paintedLine = false;
+        for (int r = 0; r < nrows && y < ymax; ++r)
+          {
+            y += height;
+            if (gap != null)
+              y += gap.height;
+            gfx.drawLine(x0, y, xmax, y);
+            paintedLine = true;
+          }
+        gfx.setColor(save);
+      }
+
+  }
+
+}
diff --git a/libjava/javax/swing/plaf/basic/BasicTextAreaUI.java b/libjava/javax/swing/plaf/basic/BasicTextAreaUI.java
new file mode 100644 (file)
index 0000000..f1714c2
--- /dev/null
@@ -0,0 +1,69 @@
+/* BasicTextAreaUI.java -- 
+   Copyright (C) 2004  Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package javax.swing.plaf.basic;
+
+import java.beans.PropertyChangeEvent;
+
+import javax.swing.JComponent;
+import javax.swing.plaf.ComponentUI;
+import javax.swing.text.Element;
+import javax.swing.text.PlainView;
+import javax.swing.text.View;
+
+public class BasicTextAreaUI extends BasicTextUI
+{
+  public static ComponentUI createUI(JComponent comp)
+  {
+    return new BasicTextAreaUI();
+  }
+
+  public BasicTextAreaUI()
+  {
+  }
+
+  public View create(Element elem)
+  {
+    return new PlainView(elem);
+  }
+
+  protected String getPropertyPrefix()
+  {
+    return "TextArea";
+  }
+}
diff --git a/libjava/javax/swing/plaf/basic/BasicToolTipUI.java b/libjava/javax/swing/plaf/basic/BasicToolTipUI.java
new file mode 100644 (file)
index 0000000..3b5941f
--- /dev/null
@@ -0,0 +1,287 @@
+/* BasicToolTipUI.java --
+   Copyright (C) 2004 Free Software Foundation, Inc.
+
+   This file is part of GNU Classpath.
+
+   GNU Classpath is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   GNU Classpath is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with GNU Classpath; see the file COPYING.  If not, write to the
+   Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.
+
+   Linking this library statically or dynamically with other modules is
+   making a combined work based on this library.  Thus, the terms and
+   conditions of the GNU General Public License cover the whole
+   combination.
+
+   As a special exception, the copyright holders of this library give you
+   permission to link this library with independent modules to produce an
+   executable, regardless of the license terms of these independent
+   modules, and to copy and distribute the resulting executable under
+   terms of your choice, provided that you also meet, for each linked
+   independent module, the terms and conditions of the license of that
+   module.  An independent module is a module which is not derived from
+   or based on this library.  If you modify this library, you may extend
+   this exception to your version of the library, but you are not
+   obligated to do so.  If you do not wish to do so, delete this
+   exception statement from your version. */
+
+package javax.swing.plaf.basic;
+
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Dimension;
+import java.awt.FontMetrics;
+import java.awt.Graphics;
+import java.awt.Insets;
+import java.awt.Rectangle;
+import javax.swing.JComponent;
+import javax.swing.JToolTip;
+import javax.swing.SwingConstants;
+import javax.swing.SwingUtilities;
+import javax.swing.UIDefaults;
+import javax.swing.UIManager;
+import javax.swing.border.Border;
+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 default Border around the JToolTip. */
+  private static Border defaultBorder = new Border()
+    {
+      // FIXME: This needs to go into Basic Look and Feel
+      // defaults.
+
+                       /**
+                        * This method returns the border insets.
+                        *
+                        * @param c The Component to find Border insets for.
+                        *
+                        * @return The Border insets.
+                        */              
+      public Insets getBorderInsets(Component c)
+      {
+       return new Insets(4, 4, 4, 4);
+      }
+
+                       /**
+                        * This method returns whether the border is opaque.
+                        *
+                        * @return Whether the border is opaque.
+                        */
+      public boolean isBorderOpaque()
+      {
+       return false;
+      }
+
+                       /**
+                        * This method paints the border.
+                        *
+                        * @param c The Component to paint this border around.
+                        * @param g The Graphics object to paint with.
+                        * @param x The x coordinate to start painting at.
+                        * @param y The y coordinate to start painting at.
+                        * @param w The width of the Component.
+                        * @param y The height of the Component.
+                        */
+      public void paintBorder(Component c, Graphics g, int x, int y, int w,
+                              int h)
+      {
+       Color saved = g.getColor();
+       g.setColor(Color.BLACK);
+
+       g.drawRect(0, 0, w - 1, h - 1);
+
+       g.setColor(saved);
+      }
+    };
+
+       /** The shared instance of BasicToolTipUI used for all ToolTips. */
+       private static BasicToolTipUI shared;
+
+  /**
+   * 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;
+    Rectangle vr = new Rectangle();
+    Rectangle ir = new Rectangle();
+    Rectangle tr = new Rectangle();
+    Insets insets = tip.getInsets();
+    FontMetrics fm = tip.getToolkit().getFontMetrics(tip.getFont());
+    SwingUtilities.layoutCompoundLabel(tip, fm, tip.getTipText(), 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)
+  {
+    UIDefaults defaults = UIManager.getLookAndFeelDefaults();
+    c.setBackground(defaults.getColor("ToolTip.background"));
+    c.setForeground(defaults.getColor("ToolTip.foreground"));
+    c.setFont(defaults.getFont("ToolTip.font"));
+    c.setBorder(defaultBorder);
+  }
+
+  /**
+   * This method installs the listeners for the given JComponent.
+   *
+   * @param c The JComponent to install listeners for.
+   */
+  protected void installListeners(JComponent c)
+  {
+  }
+
+  /**
+   * 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();
+    if (text == null)
+      return;
+
+    Rectangle vr = new Rectangle();
+    vr = SwingUtilities.calculateInnerArea(tip, vr);
+    Rectangle ir = new Rectangle();
+    Rectangle tr = new Rectangle();
+    FontMetrics fm = tip.getToolkit().getFontMetrics(tip.getFont());
+    SwingUtilities.layoutCompoundLabel(tip, fm, tip.getTipText(), 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 + fm.getAscent());
+
+    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)
+  {
+  }
+
+  /**
+   * This method uninstalls the UI for the given JComponent.
+   *
+   * @param c The JComponent to uninstall.
+   */
+  public void uninstallUI(JComponent c)
+  {
+    uninstallDefaults(c);
+    uninstallListeners(c);
+  }
+}
diff --git a/libjava/javax/swing/plaf/basic/ComboPopup.java b/libjava/javax/swing/plaf/basic/ComboPopup.java
new file mode 100644 (file)
index 0000000..d4ef1f2
--- /dev/null
@@ -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., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+package javax.swing.plaf.basic;
+
+import java.awt.event.KeyListener;
+import java.awt.event.MouseEvent;
+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();
+}
diff --git a/libjava/javax/swing/text/SimpleAttributeSet.java b/libjava/javax/swing/text/SimpleAttributeSet.java
new file mode 100644 (file)
index 0000000..746056d
--- /dev/null
@@ -0,0 +1,192 @@
+/* SimpleAttributeSet.java --
+   Copyright (C) 2004 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+package javax.swing.text;
+
+import java.io.Serializable;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.lang.Cloneable;
+
+public class SimpleAttributeSet
+  implements MutableAttributeSet, Serializable, Cloneable
+{
+  Hashtable tab;
+
+  static AttributeSet EMPTY = new SimpleAttributeSet();
+
+  public SimpleAttributeSet()
+  {
+    this(null);
+  }
+  
+  public SimpleAttributeSet(AttributeSet a)
+  {
+    tab = new Hashtable();
+    addAttributes(a);
+  }
+
+  public void addAttribute(Object name, Object value)
+  {
+    tab.put(name, value);
+  }
+
+  public void addAttributes(AttributeSet attributes)
+  {
+    Enumeration e = attributes.getAttributeNames();
+    while (e.hasMoreElements())
+      {
+        Object name = e.nextElement();
+        Object val = attributes.getAttribute(name);
+        tab.put(name, val);
+      }
+  }
+
+  public Object clone()
+  {
+    SimpleAttributeSet s = new SimpleAttributeSet();
+    s.tab = (Hashtable) tab.clone();
+    return s;
+  }
+
+  public boolean containsAttribute(Object name, Object value)
+  {
+    return tab.containsKey(name) 
+      && tab.get(name).equals(value);
+  }
+    
+  public boolean containsAttributes(AttributeSet attributes)
+  {
+    Enumeration e = attributes.getAttributeNames();
+    while (e.hasMoreElements())
+      {
+        Object name = e.nextElement();
+        Object val = attributes.getAttribute(name);
+        if (! containsAttribute(name, val))
+          return false;                
+      }
+    return true;
+  }
+
+  public AttributeSet copyAttributes()
+  {
+    return (AttributeSet) clone();
+  }
+
+  public boolean equals(Object obj)
+  {
+    return (obj != null) 
+      && (obj instanceof SimpleAttributeSet)
+      && ((SimpleAttributeSet)obj).tab.equals(this.tab);
+  }
+
+  public Object getAttribute(Object name)
+  {
+    Object val = tab.get(name);
+    if (val != null) 
+      return val;
+
+    Object p = getResolveParent();
+    if (p != null && p instanceof AttributeSet)
+      return (((AttributeSet)p).getAttribute(name));
+
+    return null;
+  }
+
+  public int getAttributeCount()
+  {
+    return tab.size();
+  }
+
+  public Enumeration getAttributeNames()
+  {
+    return tab.keys();
+  }
+
+  public AttributeSet getResolveParent()
+  {
+    return (AttributeSet) tab.get(ResolveAttribute);
+  }
+
+  public int hashCode()
+  {
+    return tab.hashCode();
+  }
+
+  public boolean isDefined(Object attrName)
+  {
+    return tab.containsKey(attrName);
+  }
+
+  public boolean isEmpty()
+  {
+    return tab.isEmpty();      
+  }
+        
+  public boolean isEqual(AttributeSet attr)
+  {
+    return this.equals(attr);
+  }
+    
+  public void removeAttribute(Object name)
+  {
+    tab.remove(name);
+  }
+
+  public void removeAttributes(AttributeSet attributes)
+  {
+    removeAttributes(attributes.getAttributeNames());
+  }
+
+  public void removeAttributes(Enumeration names)
+  {
+    while (names.hasMoreElements())
+      {
+        removeAttribute(names.nextElement());
+      }        
+  }
+
+  public void setResolveParent(AttributeSet parent)
+  {
+    addAttribute(ResolveAttribute, parent);
+  }
+    
+  public String toString()
+  {
+    return tab.toString();
+  }    
+}
diff --git a/libjava/javax/swing/text/StyleConstants.java b/libjava/javax/swing/text/StyleConstants.java
new file mode 100644 (file)
index 0000000..2201c47
--- /dev/null
@@ -0,0 +1,439 @@
+/* StyleConstants.java --
+   Copyright (C) 2004 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+package javax.swing.text;
+
+import java.awt.Color;
+import java.awt.Component;
+import javax.swing.Icon;
+
+public class StyleConstants
+{
+
+  String keyname;
+  private StyleConstants(String k) 
+  {
+    keyname = k;
+  }
+
+  public String toString()
+  {
+    return keyname;
+  }
+
+  public static int ALIGN_CENTER;
+  public static int ALIGN_JUSTIFIED;
+  public static int ALIGN_LEFT;
+  public static int ALIGN_RIGHT;
+
+  public static Object Background = CharacterConstants.Background;
+  public static Object BidiLevel = CharacterConstants.BidiLevel;
+  public static Object Bold = CharacterConstants.Bold;
+  public static Object ComponentAttribute = CharacterConstants.ComponentAttribute;
+  public static Object FontFamily = CharacterConstants.Family;
+  public static Object FontSize = CharacterConstants.Size;
+  public static Object Foreground = CharacterConstants.Foreground;
+  public static Object IconAttribute = CharacterConstants.IconAttribute;
+  public static Object Italic = CharacterConstants.Italic;
+  public static Object StrikeThrough = CharacterConstants.StrikeThrough;
+  public static Object Subscript = CharacterConstants.Subscript;
+  public static Object Superscript = CharacterConstants.Superscript;
+  public static Object Underline = CharacterConstants.Underline;
+
+  public static Object Alignment = ParagraphConstants.Alignment;
+  public static Object FirstLineIndent = ParagraphConstants.FirstLineIndent;
+  public static Object LeftIndent = ParagraphConstants.LeftIndent;
+  public static Object LineSpacing = ParagraphConstants.LineSpacing;
+  public static Object Orientation = ParagraphConstants.Orientation;
+  public static Object RightIndent = ParagraphConstants.RightIndent;
+  public static Object SpaceAbove = ParagraphConstants.SpaceAbove;
+  public static Object SpaceBelow = ParagraphConstants.SpaceBelow;
+  public static Object TabSet = ParagraphConstants.TabSet;
+
+  public static String ComponentElementName = new String("component");
+  public static String IconElementName = new String("icon");
+
+  public static Object ComposedTextAttribute = new StyleConstants("composed text");
+  public static Object ModelAttribute = new StyleConstants("model");
+  public static Object NameAttribute = new StyleConstants("name");
+  public static Object ResolveAttribute = new StyleConstants("resolver");
+
+  public static int getAlignment(AttributeSet a)
+  {
+    if (a.isDefined(Alignment))
+      return ((Integer)a.getAttribute(Alignment)).intValue();
+    else
+      return ALIGN_LEFT;      
+  } 
+
+  public static Color getBackground(AttributeSet a)
+  {
+    if (a.isDefined(Background))
+      return (Color) a.getAttribute(Background);
+    else
+      return Color.BLACK;
+  } 
+  
+  public static int getBidiLevel(AttributeSet a)
+  {
+    if (a.isDefined(BidiLevel))
+      return ((Integer)a.getAttribute(BidiLevel)).intValue();
+    else
+      return 0;
+  } 
+
+  public static Component getComponent(AttributeSet a)
+  {
+    if (a.isDefined(ComponentAttribute))
+      return (Component) a.getAttribute(ComponentAttribute);
+    else
+      return (Component) null;
+  } 
+
+  public static float getFirstLineIndent(AttributeSet a)
+  {
+    if (a.isDefined(FirstLineIndent))
+      return ((Float)a.getAttribute(FirstLineIndent)).floatValue();
+    else
+      return 0.f;
+  } 
+
+  public static String getFontFamily(AttributeSet a)
+  {
+    if (a.isDefined(FontFamily))
+      return (String) a.getAttribute(FontFamily);
+    else
+      return "Monospaced";
+  } 
+
+  public static int getFontSize(AttributeSet a)
+  {
+    if (a.isDefined(FontSize))
+      return ((Integer)a.getAttribute(FontSize)).intValue();
+    else
+      return 12;
+  } 
+
+  public static Color getForeground(AttributeSet a)
+  {
+    if (a.isDefined(Foreground))
+      return (Color) a.getAttribute(Foreground);
+    else
+      return Color.BLACK;
+  } 
+
+  public static Icon getIcon(AttributeSet a)
+  {
+    if (a.isDefined(IconAttribute))
+      return (Icon) a.getAttribute(IconAttribute);
+    else
+      return (Icon) null;
+  } 
+
+  public static float getLeftIndent(AttributeSet a)
+  {
+    if (a.isDefined(LeftIndent))
+      return ((Float)a.getAttribute(LeftIndent)).floatValue();
+    else
+      return 0.f;  
+  } 
+
+  public static float getLineSpacing(AttributeSet a)
+  {
+    if (a.isDefined(LineSpacing))
+      return ((Float)a.getAttribute(LineSpacing)).floatValue();
+    else
+      return 0.f;  
+  } 
+
+  public static float getRightIndent(AttributeSet a)
+  {
+    if (a.isDefined(RightIndent))
+      return ((Float)a.getAttribute(RightIndent)).floatValue();
+    else
+      return 0.f;  
+  } 
+
+  public static float getSpaceAbove(AttributeSet a)
+  {
+    if (a.isDefined(SpaceAbove))
+      return ((Float)a.getAttribute(SpaceAbove)).floatValue();
+    else
+      return 0.f;  
+  } 
+
+  public static float getSpaceBelow(AttributeSet a)
+  {
+    if (a.isDefined(SpaceBelow))
+      return ((Float)a.getAttribute(SpaceBelow)).floatValue();
+    else
+      return 0.f;  
+  } 
+
+  public static javax.swing.text.TabSet getTabSet(AttributeSet a)
+  {
+    if (a.isDefined(StyleConstants.TabSet))
+      return (javax.swing.text.TabSet) a.getAttribute(StyleConstants.TabSet);
+    else
+      return (javax.swing.text.TabSet) null;
+  } 
+
+  public static boolean isBold(AttributeSet a)
+  {
+    if (a.isDefined(Bold))
+      return ((Boolean) a.getAttribute(Bold)).booleanValue();
+    else
+      return false;    
+  } 
+
+  public static boolean isItalic(AttributeSet a)
+  {
+    if (a.isDefined(Italic))
+      return ((Boolean) a.getAttribute(Italic)).booleanValue();
+    else
+      return false;    
+  } 
+
+  public static boolean isStrikeThrough(AttributeSet a)
+  {
+    if (a.isDefined(StrikeThrough))
+      return ((Boolean) a.getAttribute(StrikeThrough)).booleanValue();
+    else
+      return false;    
+  } 
+
+  public static boolean isSubscript(AttributeSet a)
+  {
+    if (a.isDefined(Subscript))
+      return ((Boolean) a.getAttribute(Subscript)).booleanValue();
+    else
+      return false;    
+  } 
+
+  public static boolean isSuperscript(AttributeSet a)
+  {
+    if (a.isDefined(Superscript))
+      return ((Boolean) a.getAttribute(Superscript)).booleanValue();
+    else
+      return false;    
+  } 
+
+  public static boolean isUnderline(AttributeSet a)
+  {
+    if (a.isDefined(Underline))
+      return ((Boolean) a.getAttribute(Underline)).booleanValue();
+    else
+      return false;    
+  } 
+
+  public static void setAlignment(MutableAttributeSet a, int align)
+  {
+    a.addAttribute(Alignment, new Integer(align));
+  } 
+
+  public static void setBackground(MutableAttributeSet a, Color fg)
+  {
+    a.addAttribute(Background, fg);
+  } 
+
+  public static void setBidiLevel(MutableAttributeSet a, int lev)
+  {
+    a.addAttribute(BidiLevel, new Integer(lev));
+  } 
+
+  public static void setBold(MutableAttributeSet a, boolean b)
+  {
+    a.addAttribute(Bold, new Boolean(b));
+  } 
+  
+  public static void setComponent(MutableAttributeSet a, Component c)
+  {
+    a.addAttribute(ComponentAttribute, c);
+  } 
+
+  public static void setFirstLineIndent(MutableAttributeSet a, float i)
+  {
+    a.addAttribute(FirstLineIndent, new Float(i));
+  } 
+
+  public static void setFontFamily(MutableAttributeSet a, String fam)
+  {
+    a.addAttribute(FontFamily, fam);
+  } 
+
+  public static void setFontSize(MutableAttributeSet a, int s)
+  {
+    a.addAttribute(FontSize, new Integer(s));
+  } 
+
+  public static void setForeground(MutableAttributeSet a, Color fg)
+  {
+    a.addAttribute(Foreground, fg);
+  }
+
+  public static void setIcon(MutableAttributeSet a, Icon c)
+  {
+    a.addAttribute(IconAttribute, c);
+  }
+  public static void setItalic(MutableAttributeSet a, boolean b)
+  {
+    a.addAttribute(Italic, new Boolean(b));
+  }
+  public static void setLeftIndent(MutableAttributeSet a, float i)
+  {
+    a.addAttribute(LeftIndent, new Float(i));
+  } 
+
+  public static void setLineSpacing(MutableAttributeSet a, float i)
+  {
+    a.addAttribute(LineSpacing, new Float(i));
+  } 
+
+  public static void setRightIndent(MutableAttributeSet a, float i)
+  {
+    a.addAttribute(RightIndent, new Float(i));
+  } 
+
+  public static void setSpaceAbove(MutableAttributeSet a, float i)
+  {
+    a.addAttribute(SpaceAbove, new Float(i));
+  } 
+
+  public static void setSpaceBelow(MutableAttributeSet a, float i)
+  {
+    a.addAttribute(SpaceBelow, new Float(i));
+  } 
+
+  public static void setStrikeThrough(MutableAttributeSet a, boolean b)
+  {
+    a.addAttribute(StrikeThrough, new Boolean(b));
+  } 
+
+  public static void setSubscript(MutableAttributeSet a, boolean b)
+  {
+    a.addAttribute(Subscript, new Boolean(b));
+  } 
+
+  public static void setSuperscript(MutableAttributeSet a, boolean b)
+  {
+    a.addAttribute(Superscript, new Boolean(b));
+  } 
+
+  public static void setTabSet(MutableAttributeSet a, javax.swing.text.TabSet tabs)
+  {
+    a.addAttribute(StyleConstants.TabSet, tabs);
+  } 
+
+  public static void setUnderline(MutableAttributeSet a, boolean b)
+  {
+    a.addAttribute(Underline, new Boolean(b));
+  } 
+
+  // The remainder are so-called "typesafe enumerations" which 
+  // alias subsets of the above constants.
+  public static class CharacterConstants
+    extends StyleConstants
+    implements AttributeSet.CharacterAttribute
+  {
+    private CharacterConstants(String k) 
+    {
+      super(k);
+    }
+    
+    public static Object Background = ColorConstants.Background;
+    public static Object BidiLevel = new CharacterConstants("bidiLevel");
+    public static Object Bold = FontConstants.Bold;
+    public static Object ComponentAttribute = new CharacterConstants("component");
+    public static Object Family = FontConstants.Family;
+    public static Object Size = FontConstants.Size;
+    public static Object Foreground = ColorConstants.Foreground;
+    public static Object IconAttribute = new CharacterConstants("icon");
+    public static Object Italic = FontConstants.Italic;
+    public static Object StrikeThrough = new CharacterConstants("strikethrough");
+    public static Object Subscript = new CharacterConstants("subscript");
+    public static Object Superscript = new CharacterConstants("superscript");
+    public static Object Underline = new CharacterConstants("underline");
+  }
+
+  public static class ColorConstants
+    extends StyleConstants
+    implements AttributeSet.ColorAttribute, AttributeSet.CharacterAttribute
+  {
+    private ColorConstants(String k) 
+    {
+      super(k);
+    }
+    public static Object Foreground = new ColorConstants("foreground");
+    public static Object Background = new ColorConstants("background");
+  }
+
+  public static class FontConstants
+    extends StyleConstants
+    implements AttributeSet.FontAttribute, AttributeSet.CharacterAttribute
+  {
+    private FontConstants(String k) 
+    {
+      super(k);
+    }
+    public static Object Bold = new FontConstants("bold");
+    public static Object Family = new FontConstants("family");
+    public static Object Italic = new FontConstants("italic");
+    public static Object Size = new FontConstants("size");
+  }
+
+  public static class ParagraphConstants
+    extends StyleConstants
+    implements AttributeSet.ParagraphAttribute
+  {
+    private ParagraphConstants(String k) 
+    {
+      super(k);
+    }
+    public static Object Alignment = new ParagraphConstants("Alignment");
+    public static Object FirstLineIndent = new ParagraphConstants("FirstLineIndent");
+    public static Object LeftIndent = new ParagraphConstants("LeftIndent");
+    public static Object LineSpacing = new ParagraphConstants("LineSpacing");
+    public static Object Orientation = new ParagraphConstants("Orientation");
+    public static Object RightIndent = new ParagraphConstants("RightIndent");
+    public static Object SpaceAbove = new ParagraphConstants("SpaceAbove");
+    public static Object SpaceBelow = new ParagraphConstants("SpaceBelow");
+    public static Object TabSet = new ParagraphConstants("TabSet");
+  }
+
+}
diff --git a/libjava/javax/swing/text/StyleContext.java b/libjava/javax/swing/text/StyleContext.java
new file mode 100644 (file)
index 0000000..8accd9b
--- /dev/null
@@ -0,0 +1,697 @@
+/* StyleContext.java --
+   Copyright (C) 2004 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+package javax.swing.text;
+
+import java.awt.Color;
+import java.awt.Font;
+import java.awt.FontMetrics;
+import java.awt.Toolkit;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+import javax.swing.event.EventListenerList;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+import java.util.Enumeration;
+import java.util.EventListener;
+import java.util.Hashtable;
+
+public class StyleContext 
+    implements Serializable, AbstractDocument.AttributeContext
+{
+  public class NamedStyle
+    implements Serializable, Style
+  {
+    protected ChangeEvent changeEvent;
+    protected EventListenerList listenerList;
+      
+    AttributeSet attributes;
+    String name;
+
+    public NamedStyle()
+    {
+      this(null, null);
+    }
+
+    public NamedStyle(Style parent)
+    {
+      this(null, parent);
+    }
+
+    public NamedStyle(String name, Style parent)
+    {
+      this.name = name;
+      this.attributes = getEmptySet();
+      this.changeEvent = new ChangeEvent(this);
+      this.listenerList = new EventListenerList();
+      setResolveParent(parent);
+    }
+
+    public String getName()
+    {
+      return name;
+    }
+
+    public void setName(String n)
+    {
+      name = n;
+      fireStateChanged();
+    }
+
+    public void addChangeListener(ChangeListener l)
+    {
+      listenerList.add(ChangeListener.class, l);
+    }
+      
+    public void removeChangeListener(ChangeListener l)
+    {
+      listenerList.remove(ChangeListener.class, l);
+    }
+      
+    public EventListener[] getListeners(Class listenerType)
+    {
+      return listenerList.getListeners(listenerType);
+    }
+
+    public ChangeListener[] getChangeListeners()
+    {
+      return (ChangeListener[]) getListeners(ChangeListener.class);
+    }
+
+    protected  void fireStateChanged()
+    {
+      ChangeListener[] listeners = getChangeListeners();
+      for (int i = 0; i < listeners.length; ++i)
+        {
+          listeners[i].stateChanged(changeEvent);
+        }
+    }
+
+    public void addAttribute(Object name, Object value)
+    {
+      attributes = StyleContext.this.addAttribute(attributes, name, value);
+      fireStateChanged();
+    }
+
+    public void addAttributes(AttributeSet attr)
+    {
+      attributes = StyleContext.this.addAttributes(attributes, attr);
+      fireStateChanged();
+    }
+
+    public boolean containsAttribute(Object name, Object value)
+    {
+      return attributes.containsAttribute(name, value);
+    }
+      
+    public boolean containsAttributes(AttributeSet attrs)
+    {
+      return attributes.containsAttributes(attrs);
+    }
+
+    public AttributeSet copyAttributes()
+    {
+      return attributes.copyAttributes();
+    }
+            
+    public Object getAttribute(Object attrName)
+    {
+      return attributes.getAttribute(attrName);
+    }
+
+    public int getAttributeCount()
+    {
+      return attributes.getAttributeCount();
+    }
+
+    public Enumeration getAttributeNames()
+    {
+      return attributes.getAttributeNames();
+    }
+      
+    public boolean isDefined(Object attrName)
+    {
+      return attributes.isDefined(attrName);        
+    }
+
+    public boolean isEqual(AttributeSet attr)
+    {
+      return attributes.isEqual(attr);
+    }
+
+    public void removeAttribute(Object name)
+    {
+      attributes = StyleContext.this.removeAttribute(attributes, name);
+      fireStateChanged();
+    }
+
+    public void removeAttributes(AttributeSet attrs)
+    {
+      attributes = StyleContext.this.removeAttributes(attributes, attrs);
+      fireStateChanged();
+    }
+
+    public void removeAttributes(Enumeration names)
+    {
+      attributes = StyleContext.this.removeAttributes(attributes, names);
+      fireStateChanged();
+    }
+
+
+    public AttributeSet getResolveParent()
+    {
+      return attributes.getResolveParent();        
+    }
+
+    public void setResolveParent(AttributeSet parent)
+    {
+      attributes = StyleContext.this.addAttribute(attributes, ResolveAttribute, parent);
+      fireStateChanged();
+    }
+      
+    public String toString()
+    {
+      return ("[NamedStyle: name=" + name + ", attrs=" + attributes.toString() + "]");
+    }      
+  }
+  
+  public class SmallAttributeSet
+    implements AttributeSet
+  {
+    final Object [] attrs;
+    public SmallAttributeSet(AttributeSet a)
+    {
+      if (a == null)
+        attrs = new Object[0];
+      else
+        {
+          int n = a.getAttributeCount();
+          int i = 0;
+          attrs = new Object[n * 2];
+          Enumeration e = a.getAttributeNames();
+          while (e.hasMoreElements())
+            {
+              Object name = e.nextElement();
+              attrs[i++] = name;
+              attrs[i++] = a.getAttribute(name);
+            }
+        }
+    }
+
+    public SmallAttributeSet(Object [] a)
+    {
+      if (a == null)
+        attrs = new Object[0];
+      else
+        {
+          attrs = new Object[a.length];
+          System.arraycopy(a, 0, attrs, 0, a.length);
+        }
+    }
+
+    public Object clone()
+    {
+      return new SmallAttributeSet(this.attrs);
+    }
+
+    public boolean containsAttribute(Object name, Object value)
+    {
+      for (int i = 0; i < attrs.length; i += 2)
+        {
+          if (attrs[i].equals(name) &&
+              attrs[i+1].equals(value))
+            return true;
+        }
+      return false;
+    }
+
+    public boolean containsAttributes(AttributeSet a)
+    {
+      Enumeration e = a.getAttributeNames();
+      while (e.hasMoreElements())
+        {
+          Object name = e.nextElement();
+          Object val = a.getAttribute(name);
+          if (!containsAttribute(name, val))
+            return false;
+        }
+      return true;                     
+    }
+
+    public AttributeSet copyAttributes()
+    {
+      return (AttributeSet) clone();
+    }
+
+    public boolean equals(Object obj)
+    {
+      return 
+        (obj instanceof SmallAttributeSet)
+        && this.isEqual((AttributeSet)obj);
+    }
+    public Object getAttribute(Object key)
+    {
+      for (int i = 0; i < attrs.length; i += 2)
+        {
+          if (attrs[i].equals(key))
+            return attrs[i+1];
+        }
+            
+      Object p = getResolveParent();
+      if (p != null && p instanceof AttributeSet)
+        return (((AttributeSet)p).getAttribute(key));
+      
+      return null;
+    }
+
+    public int getAttributeCount()
+    {
+      return attrs.length / 2;
+    }
+
+    public Enumeration getAttributeNames()
+    {      
+      return new Enumeration() 
+        {
+          int i = 0;
+          public boolean hasMoreElements() 
+          { 
+            return i < attrs.length; 
+          }
+          public Object nextElement() 
+          { 
+            i += 2; 
+            return attrs[i-2]; 
+          }
+        };
+    }
+
+    public AttributeSet getResolveParent()
+    {
+      return (AttributeSet) getAttribute(ResolveAttribute);
+    }
+
+    public int hashCode()
+    {
+      return java.util.Arrays.asList(attrs).hashCode();
+    }
+
+    public boolean isDefined(Object key)
+    {
+      for (int i = 0; i < attrs.length; i += 2)
+        {
+          if (attrs[i].equals(key))
+            return true;
+        }
+      return false;
+    }
+       
+    public boolean isEqual(AttributeSet attr)
+    {
+      return attr != null 
+        && attr.containsAttributes(this)
+        && this.containsAttributes(attr);
+    }
+       
+    public String toString()
+    {
+      StringBuffer sb = new StringBuffer();
+      sb.append("[StyleContext.SmallattributeSet:");
+      for (int i = 0; i < attrs.length; ++i)
+        {
+          sb.append(" (");
+          sb.append(attrs[i].toString());
+          sb.append("=");
+          sb.append(attrs[i+1].toString());
+          sb.append(")");
+        }
+      sb.append("]");
+      return sb.toString();
+    }
+  }
+
+  // FIXME: official javadocs suggest that these might be more usefully
+  // implemented using a WeakHashMap, but not sure if that works most
+  // places or whether it really matters anyways.
+  //
+  // FIXME: also not sure if these tables ought to be static (singletons),
+  // shared across all StyleContexts. I think so, but it's not clear in
+  // docs. revert to non-shared if you think it matters.
+
+  public static final String DEFAULT_STYLE = "default";
+  
+  static Hashtable sharedAttributeSets = new Hashtable();
+  static Hashtable sharedFonts = new Hashtable();
+
+  static StyleContext defaultStyleContext = new StyleContext();
+  static final int compressionThreshold = 9;
+  
+  EventListenerList listenerList;
+  Hashtable styleTable;
+  
+  public StyleContext()
+  {
+    listenerList = new EventListenerList();
+    styleTable = new Hashtable();
+  }
+
+  protected SmallAttributeSet createSmallAttributeSet(AttributeSet a)
+  {
+    return new SmallAttributeSet(a);
+  }
+  
+  protected MutableAttributeSet createLargeAttributeSet(AttributeSet a)
+  {
+    return new SimpleAttributeSet(a);
+  }
+
+  public void addChangeListener(ChangeListener listener)
+  {
+    listenerList.add(ChangeListener.class, listener);
+  }
+
+  public void removeChangeListener(ChangeListener listener)
+  {
+    listenerList.remove(ChangeListener.class, listener);
+  }
+
+  public ChangeListener[] getChangeListeners()
+  {
+    return (ChangeListener[]) listenerList.getListeners(ChangeListener.class);
+  }
+    
+  public Style addStyle(String name, Style parent)
+  {
+    Style newStyle = new NamedStyle(name, parent);
+    if (name != null)
+      styleTable.put(name, newStyle);
+    return newStyle;
+  }
+
+  public void removeStyle(String name)
+  {
+    styleTable.remove(name);
+  }
+
+  public Style getStyle(String name)
+  {
+    return (Style) styleTable.get(name);
+  }
+
+  public Enumeration getStyleNames()
+  {
+    return styleTable.keys();
+  }
+
+  //
+  // StyleContexts only understand the "simple" model of fonts present in
+  // pre-java2d systems: fonts are a family name, a size (integral number
+  // of points), and a mask of style parameters (plain, bold, italic, or
+  // bold|italic). We have an inner class here called SimpleFontSpec which
+  // holds such triples.
+  //
+  // A SimpleFontSpec can be built for *any* AttributeSet because the size,
+  // family, and style keys in an AttributeSet have default values (defined
+  // over in StyleConstants).
+  //
+  // We keep a static cache mapping SimpleFontSpecs to java.awt.Fonts, so
+  // that we reuse Fonts between styles and style contexts.
+  // 
+
+  private static class SimpleFontSpec
+  {
+    String family;
+    int style;
+    int size;
+    public SimpleFontSpec(String family,
+                          int style,
+                          int size)
+    {
+      this.family = family;
+      this.style = style;
+      this.size = size;
+    }
+    public boolean equals(Object obj)
+    {
+      return (obj != null)
+        && (obj instanceof SimpleFontSpec)
+        && (((SimpleFontSpec)obj).family.equals(this.family))
+        && (((SimpleFontSpec)obj).style == this.style)
+        && (((SimpleFontSpec)obj).size == this.size);
+    }
+    public int hashCode()
+    {
+      return family.hashCode() + style + size;
+    }
+  }
+  
+  public Font getFont(AttributeSet attr)
+  {
+    String family = StyleConstants.getFontFamily(attr);
+    int style = Font.PLAIN;
+    if (StyleConstants.isBold(attr))
+      style += Font.BOLD;
+    if (StyleConstants.isItalic(attr))
+      style += Font.ITALIC;      
+    int size = StyleConstants.getFontSize(attr);
+    return getFont(family, style, size);
+  }
+
+  public Font getFont(String family, int style, int size)
+  {
+    SimpleFontSpec spec = new SimpleFontSpec(family, style, size);
+    if (sharedFonts.containsKey(spec))
+      return (Font) sharedFonts.get(spec);
+    else
+      {
+        Font tmp = new Font(family, style, size);
+        sharedFonts.put(spec, tmp);
+        return tmp;
+      }
+  }
+  
+  public FontMetrics getFontMetrics(Font f)
+  {
+    return Toolkit.getDefaultToolkit().getFontMetrics(f);
+  }
+
+  public Color getForeground(AttributeSet a)
+  {
+    return StyleConstants.getForeground(a);
+  }
+
+  public Color getBackground(AttributeSet a)
+  {
+    return StyleConstants.getBackground(a);
+  }
+
+  protected int getCompressionThreshold() 
+  {
+    return compressionThreshold;
+  }
+
+  public static StyleContext getDefaultStyleContext()
+  {
+    return defaultStyleContext;
+  }
+
+  public AttributeSet addAttribute(AttributeSet old, Object name, Object value)
+  {
+    if (old instanceof MutableAttributeSet)
+      {
+        ((MutableAttributeSet)old).addAttribute(name, value);
+        return old;
+      }
+    else 
+      {
+        MutableAttributeSet mutable = createLargeAttributeSet(old);
+        mutable.addAttribute(name, value);
+        if (mutable.getAttributeCount() >= getCompressionThreshold())
+          return mutable;
+        else
+          {
+            SmallAttributeSet small = createSmallAttributeSet(mutable);
+            if (sharedAttributeSets.containsKey(small))
+              small = (SmallAttributeSet) sharedAttributeSets.get(small);
+            else
+              sharedAttributeSets.put(small,small);
+            return small;
+          }
+      }
+  }
+
+  public AttributeSet addAttributes(AttributeSet old, AttributeSet attributes)
+  {
+    if (old instanceof MutableAttributeSet)
+      {
+        ((MutableAttributeSet)old).addAttributes(attributes);
+        return old;
+      }
+    else 
+      {
+        MutableAttributeSet mutable = createLargeAttributeSet(old);
+        mutable.addAttributes(attributes);
+        if (mutable.getAttributeCount() >= getCompressionThreshold())
+          return mutable;
+        else
+          {
+            SmallAttributeSet small = createSmallAttributeSet(mutable);
+            if (sharedAttributeSets.containsKey(small))
+              small = (SmallAttributeSet) sharedAttributeSets.get(small);
+            else
+              sharedAttributeSets.put(small,small);
+            return small;
+          }
+      }
+  }
+
+  public AttributeSet getEmptySet()
+  {
+    AttributeSet e = createSmallAttributeSet(null);
+    if (sharedAttributeSets.containsKey(e))
+      e = (AttributeSet) sharedAttributeSets.get(e);
+    else
+      sharedAttributeSets.put(e, e);
+    return e;
+  }
+
+  public void reclaim(AttributeSet attributes)
+  {
+    if (sharedAttributeSets.containsKey(attributes))
+      sharedAttributeSets.remove(attributes);
+  }
+
+  public AttributeSet removeAttribute(AttributeSet old, Object name)
+  {
+    if (old instanceof MutableAttributeSet)
+      {
+        ((MutableAttributeSet)old).removeAttribute(name);
+        if (old.getAttributeCount() < getCompressionThreshold())
+          {
+            SmallAttributeSet small = createSmallAttributeSet(old);
+            if (!sharedAttributeSets.containsKey(small))
+              sharedAttributeSets.put(small,small);
+            old = (AttributeSet) sharedAttributeSets.get(small);
+          }
+        return old;
+      }
+    else 
+      {          
+        MutableAttributeSet mutable = createLargeAttributeSet(old);
+        mutable.removeAttribute(name);
+        SmallAttributeSet small = createSmallAttributeSet(mutable);
+        if (sharedAttributeSets.containsKey(small))
+          small = (SmallAttributeSet) sharedAttributeSets.get(small);
+        else
+          sharedAttributeSets.put(small,small);
+        return small;
+      }
+  }
+
+  public AttributeSet removeAttributes(AttributeSet old, AttributeSet attributes)
+  {
+    return removeAttributes(old, attributes.getAttributeNames());
+  }
+
+  public AttributeSet removeAttributes(AttributeSet old, Enumeration names)
+  {
+    if (old instanceof MutableAttributeSet)
+      {
+        ((MutableAttributeSet)old).removeAttributes(names);
+        if (old.getAttributeCount() < getCompressionThreshold())
+          {
+            SmallAttributeSet small = createSmallAttributeSet(old);
+            if (!sharedAttributeSets.containsKey(small))
+              sharedAttributeSets.put(small,small);
+            old = (AttributeSet) sharedAttributeSets.get(small);
+          }
+        return old;
+      }
+    else 
+      {          
+        MutableAttributeSet mutable = createLargeAttributeSet(old);
+        mutable.removeAttributes(names);
+        SmallAttributeSet small = createSmallAttributeSet(mutable);
+        if (sharedAttributeSets.containsKey(small))
+          small = (SmallAttributeSet) sharedAttributeSets.get(small);
+        else
+          sharedAttributeSets.put(small,small);
+        return small;
+      }        
+  }
+
+
+  // FIXME: there's some sort of quasi-serialization stuff in here which I
+  // have left incomplete; I'm not sure I understand the intent properly.
+
+  public static Object getStaticAttribute(Object key)
+  {
+    throw new InternalError("not implemented");
+  }
+  
+  public static Object getStaticAttributeKey(Object key)
+  {
+    throw new InternalError("not implemented");
+  }
+
+  public static void readAttributeSet(ObjectInputStream in, MutableAttributeSet a)
+    throws ClassNotFoundException, IOException
+  {
+    throw new InternalError("not implemented");
+  }
+  
+  public static void writeAttributeSet(ObjectOutputStream out, AttributeSet a)
+    throws IOException
+  {
+    throw new InternalError("not implemented");
+  }
+
+  public void readAttributes(ObjectInputStream in, MutableAttributeSet a)
+    throws ClassNotFoundException, IOException 
+  {
+    throw new InternalError("not implemented");
+  }
+
+  public void writeAttributes(ObjectOutputStream out, AttributeSet a)
+    throws IOException
+  {
+    throw new InternalError("not implemented");
+  }
+}
diff --git a/libjava/javax/swing/text/TabSet.java b/libjava/javax/swing/text/TabSet.java
new file mode 100644 (file)
index 0000000..58ae65e
--- /dev/null
@@ -0,0 +1,102 @@
+/* TabSet.java --
+   Copyright (C) 2004 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+package javax.swing.text;
+
+import java.io.Serializable;
+
+public class TabSet implements Serializable
+{
+  TabStop[] tabs;
+
+  public TabSet(TabStop[] t) 
+  {
+    tabs = t;
+  }
+  public TabStop getTab(int i) 
+  {
+    return tabs[i];
+  }
+
+  public TabStop getTabAfter(float location) 
+  {
+    int idx = getTabIndexAfter(location);
+    if (idx == -1)
+      return null;
+    else
+      return tabs[idx];        
+  }
+
+  public int getTabCount() 
+  {
+    return tabs.length;
+  }
+
+  public int getTabIndex(TabStop tab) 
+  {
+    for (int i = 0; i < tabs.length; ++i)
+      if (tabs[i] == tab)
+        return i;
+    return -1;
+  }
+
+  public int getTabIndexAfter(float location) 
+  {
+    int idx = -1;
+    for (int i = 0; i < tabs.length; ++i)
+      {
+        if (location < tabs[i].getPosition())
+          idx = i;
+      }
+    return idx;
+  }
+
+  public String toString()
+  {
+    StringBuffer sb = new StringBuffer();
+    sb.append("[");
+    for (int i = 0; i < tabs.length; ++i)
+      {
+        if (i != 0)
+          sb.append(" - ");
+        sb.append(tabs[i].toString());
+      }
+    sb.append("]");
+    return sb.toString();
+  }
+}
diff --git a/libjava/javax/swing/text/TabStop.java b/libjava/javax/swing/text/TabStop.java
new file mode 100644 (file)
index 0000000..2c95a63
--- /dev/null
@@ -0,0 +1,133 @@
+/* TabSet.java --
+   Copyright (C) 2004 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+package javax.swing.text;
+
+import java.io.Serializable;
+
+public class TabStop implements Serializable
+{
+  public static final int ALIGN_LEFT = 0;
+  public static final int ALIGN_RIGHT = 1;
+  public static final int ALIGN_CENTER = 2;
+  public static final int ALIGN_DECIMAL = 4;
+  public static final int ALIGN_BAR = 5;
+
+  public static final int LEAD_NONE = 0;
+  public static final int LEAD_DOTS = 1;
+  public static final int LEAD_HYPHENS = 2;
+  public static final int LEAD_UNDERLINE = 3;
+  public static final int LEAD_THICKLINE = 4;
+  public static final int LEAD_EQUALS = 5;
+
+  float pos;
+  int align;
+  int leader;
+
+  public TabStop(float pos) 
+  {
+    this(pos, ALIGN_LEFT, LEAD_NONE);
+  }
+  
+  public TabStop(float pos, int align, int leader)
+  {
+    this.pos = pos;
+    this.align = align;
+    this.leader = leader;
+  }
+    
+  public boolean equals(Object other) 
+  {
+    return (other != null)
+      && (other instanceof TabStop)
+      && (((TabStop)other).getPosition() == this.getPosition())
+      && (((TabStop)other).getLeader() == this.getLeader())
+      && (((TabStop)other).getAlignment() == this.getAlignment());
+  }
+
+  public int getAlignment() 
+  {
+    return align;
+  }
+
+  public int getLeader() 
+  {
+    return leader;
+  }
+
+  public float getPosition() 
+  {
+    return pos;
+  }
+
+  public int hashCode() 
+  {
+    return (int) pos + (int) leader + (int) align;
+  }
+
+  public String toString() 
+  {
+    String prefix = "";
+    switch (align)
+      {
+      case ALIGN_LEFT:
+        prefix = "left ";
+        break;
+      case ALIGN_RIGHT:
+        prefix = "right ";
+        break;
+
+      case ALIGN_CENTER:
+        prefix = "center ";
+        break;
+
+      case ALIGN_DECIMAL:
+        prefix = "decimal ";
+        break;
+        
+      case ALIGN_BAR:
+        prefix = "bar ";
+        break;
+
+      default:
+        break;
+      }
+    
+    return (prefix + "tab @" + pos + ((leader == LEAD_NONE) ? "" : "(w/leaders)"));
+  }
+
+}
diff --git a/libjava/javax/swing/text/Utilities.java b/libjava/javax/swing/text/Utilities.java
new file mode 100644 (file)
index 0000000..61c13ee
--- /dev/null
@@ -0,0 +1,182 @@
+/* Utilities.java --
+   Copyright (C) 2004 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package javax.swing.text;
+
+import java.awt.FontMetrics;
+import java.awt.Graphics;
+
+/**
+ * A set of utilities to deal with text. This is used by several other classes
+ * inside this package.
+ *
+ * @author Roman Kennke <roman@ontographics.com>
+ */
+public class Utilities
+{
+  /**
+   * The length of the char buffer that holds the characters to be drawn.
+   */
+  private static final int BUF_LENGTH = 64;
+
+  /**
+   * Creates a new <code>Utilities</code> object.
+   */
+  public Utilities()
+  {
+    // Nothing to be done here.
+  }
+
+  /**
+   * Draws the given text segment. Contained tabs and newline characters
+   * are taken into account. Tabs are expanded using the
+   * specified {@link TabExpander}.
+   *
+   * @param s the text fragment to be drawn.
+   * @param x the x position for drawing.
+   * @param y the y position for drawing.
+   * @param g the {@link Graphics} context for drawing.
+   * @param e the {@link TabExpander} which specifies the Tab-expanding
+   *     technique.
+   * @param startOffset starting offset in the text.
+   * @return the x coordinate at the end of the drawn text.
+   */
+  public static final int drawTabbedText(Segment s, int x, int y, Graphics g,
+                                         TabExpander e, int startOffset)
+  {
+    // This buffers the chars to be drawn.
+    char[] buffer = s.array;
+
+
+    // The current x and y pixel coordinates.
+    int pixelX = x;
+    int pixelY = y;
+
+    // The font metrics of the current selected font.
+    FontMetrics metrics = g.getFontMetrics();
+    int ascent = metrics.getAscent();
+
+    for (int offset = s.offset; offset < (s.offset + s.count); ++offset)
+      {
+       switch (buffer[offset])
+         {
+         case '\t':
+           // In case we have a tab, we just 'jump' over the tab.
+           // When we have no tab expander we just use the width of 'm'.
+           if (e != null)
+             pixelX = (int) e.nextTabStop((float) pixelX,
+                                          startOffset + offset - s.offset);
+           else
+             pixelX += metrics.charWidth(' ');
+           break;
+         case '\n':
+           // In case we have a newline, we must draw
+           // the buffer and jump on the next line.
+           g.drawChars(buffer, offset, 1, pixelX, y);
+           pixelY += metrics.getHeight();
+           pixelX = x;
+           break;
+         default:
+           // Here we draw the char.
+           g.drawChars(buffer, offset, 1, pixelX, pixelY + ascent);
+           pixelX += metrics.charWidth(buffer[offset]);
+           break;
+         }
+      }
+
+    return pixelX;
+  }
+
+  /**
+   * Determines the width, that the given text <code>s</code> would take
+   * if it was printed with the given {@link java.awt.FontMetrics} on the
+   * specified screen position.
+   * @param s the text fragment
+   * @param metrics the font metrics of the font to be used
+   * @param x the x coordinate of the point at which drawing should be done
+   * @param e the {@link TabExpander} to be used
+   * @param startOffset the index in <code>s</code> where to start
+   * @returns the width of the given text s. This takes tabs and newlines
+   * into account.
+   */
+  public static final int getTabbedTextWidth(Segment s, FontMetrics metrics,
+                                             int x, TabExpander e,
+                                             int startOffset)
+  {
+    // This buffers the chars to be drawn.
+    char[] buffer = s.array;
+
+    // The current x coordinate.
+    int pixelX = x;
+
+    // The current maximum width.
+    int maxWidth = 0;
+
+    for (int offset = s.offset; offset < (s.offset + s.count); ++offset)
+      {
+       switch (buffer[offset])
+         {
+         case '\t':
+           // In case we have a tab, we just 'jump' over the tab.
+           // When we have no tab expander we just use the width of 'm'.
+           if (e != null)
+             pixelX = (int) e.nextTabStop((float) pixelX,
+                                          startOffset + offset - s.offset);
+           else
+             pixelX += metrics.charWidth(' ');
+           break;
+         case '\n':
+           // In case we have a newline, we must 'draw'
+           // the buffer and jump on the next line.
+           pixelX += metrics.charWidth(buffer[offset]);
+           maxWidth = Math.max(maxWidth, pixelX - x);
+           pixelX = x;
+           break;
+         default:
+           // Here we draw the char.
+           pixelX += metrics.charWidth(buffer[offset]);
+           break;
+         }
+      }
+
+    // Take the last line into account.
+    maxWidth = Math.max(maxWidth, pixelX - x);
+
+    return maxWidth;
+  }
+}
diff --git a/libjava/jni/gtk-peer/gnu_java_awt_peer_gtk_GThreadNativeMethodRunner.c b/libjava/jni/gtk-peer/gnu_java_awt_peer_gtk_GThreadNativeMethodRunner.c
new file mode 100644 (file)
index 0000000..44f2c39
--- /dev/null
@@ -0,0 +1,68 @@
+/* Native implementation of functions in GThreadNativeMethodRunner
+   Copyright (C) 2004 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+#include "gnu_java_awt_peer_gtk_GThreadNativeMethodRunner.h"
+#include "gthread-jni.h"
+
+/*
+ * Class:     GThreadNativeMethodRunner
+ * Method:    nativeRun
+ * Signature: (J)V
+ *
+ * Purpose: Run the C function whose function pointer is
+ * 
+ */
+JNIEXPORT void JNICALL 
+Java_gnu_java_awt_peer_gtk_GThreadNativeMethodRunner_nativeRun(JNIEnv *gdk_env, jobject lcl_obj, 
+                                        jlong funcAddr, jlong funcArg)
+{
+  /* Convert the function's address back into a pointer to a C function. */
+  void *(*funcPtr)(void *) = (void *(*)(void *)) funcAddr;
+  
+  /* We do not need to worry about the return value from funcPtr(); it's
+     just thrown away.  That is part of the g_threads spec, so no reason
+     to worry about returning it.  */
+  (void) funcPtr((void *) funcArg);
+  /* Fall off the end and terminate the thread of control. */
+}
+\f
+/* Local Variables: */
+/* c-file-style: "gnu" */
+/* End: */
+
+