From: Graydon Hoare Date: Thu, 2 Sep 2004 06:58:08 +0000 (+0000) Subject: missing added files from merge X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=61341707b3db764c90f954097bf89b0811f92965;p=gcc.git missing added files from merge From-SVN: r86958 --- diff --git a/libjava/gnu/java/awt/peer/gtk/GThreadMutex.java b/libjava/gnu/java/awt/peer/gtk/GThreadMutex.java new file mode 100644 index 00000000000..111c9a801cb --- /dev/null +++ b/libjava/gnu/java/awt/peer/gtk/GThreadMutex.java @@ -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 + lockForPotentialLockers. + + 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 + potentialLockers field. Only hold this lock for brief + moments, just long enough to check or set the value of + lockForPotentialLockers. + + 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 lockForPotentialLockers while trying to get another + lock -- if you are the mutex_trylock() implementation, and you have just + checked that potentialLockers 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 index 00000000000..a4cb35a4fff --- /dev/null +++ b/libjava/gnu/java/awt/peer/gtk/GThreadNativeMethodRunner.java @@ -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); + } +} + +// 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 index 00000000000..d2d345b8e14 --- /dev/null +++ b/libjava/javax/swing/AbstractSpinnerModel.java @@ -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 AbstractSpinnerModel. + */ + public AbstractSpinnerModel() + { + } + + /** + * Adds a ChangeListener. + * + * @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 ChangeListeners. + * + * @return all the ChangeListeners + */ + 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 ChangeEvent to all the ChangeListeners + * 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 index 00000000000..00b22d5a670 --- /dev/null +++ b/libjava/javax/swing/JSpinner.java @@ -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 SpinnerNumberModel + * + * @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 JSpinner.DefaultEditor, 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 SpinnerUI that handles this spinner + * + * @return the SpinnerUI + */ + 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 ChangeListener + * + * @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 ChangeListeners + * + * @return all the ChangeListeners + */ + public ChangeListener[] getChangeListeners() + { + return (ChangeListener[]) listenerList.getListeners(ChangeListener.class); + } + + /** + * Fires a ChangeEvent to all the ChangeListeners + * added to this JSpinner + */ + 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 JSpinner. Really, it should be a + * JSpinner.DefaultEditor, 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 index 00000000000..18588b51b76 --- /dev/null +++ b/libjava/javax/swing/SpinnerNumberModel.java @@ -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 SpinnerNumberModel with initial value 0, step 1, + * and no maximum nor minimum. + */ + public SpinnerNumberModel() + { + this(new Integer(0), null, null, new Integer(1)); + } + + /** + * Creates a SpinnerNumberModel 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 SpinnerNumberModel 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 SpinnerNumberModel with Numbers and + * Comparables. + * + * @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 <= value <= 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 <= value <= 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 index 00000000000..e64df9c4cb3 --- /dev/null +++ b/libjava/javax/swing/TransferHandler.java @@ -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 index 00000000000..dcd795a7433 --- /dev/null +++ b/libjava/javax/swing/colorchooser/DefaultHSBChooserPanel.java @@ -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 index 00000000000..93ecfc39a54 --- /dev/null +++ b/libjava/javax/swing/colorchooser/DefaultPreviewPanel.java @@ -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 index 00000000000..f6c22e88577 --- /dev/null +++ b/libjava/javax/swing/colorchooser/DefaultRGBChooserPanel.java @@ -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 index 00000000000..1413a5b2d5b --- /dev/null +++ b/libjava/javax/swing/colorchooser/DefaultSwatchChooserPanel.java @@ -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 index 00000000000..1c2dcd69545 --- /dev/null +++ b/libjava/javax/swing/plaf/basic/BasicColorChooserUI.java @@ -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 index 00000000000..a465ff9492b --- /dev/null +++ b/libjava/javax/swing/plaf/basic/BasicComboBoxEditor.java @@ -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 index 00000000000..6bf6a74d5c9 --- /dev/null +++ b/libjava/javax/swing/plaf/basic/BasicComboBoxRenderer.java @@ -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 index 00000000000..851392a0f9f --- /dev/null +++ b/libjava/javax/swing/plaf/basic/BasicComboBoxUI.java @@ -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 index 00000000000..61d2dfbcdad --- /dev/null +++ b/libjava/javax/swing/plaf/basic/BasicComboPopup.java @@ -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 index 00000000000..c61dc40a5d2 --- /dev/null +++ b/libjava/javax/swing/plaf/basic/BasicFormattedTextFieldUI.java @@ -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 index 00000000000..fe1c4902ac6 --- /dev/null +++ b/libjava/javax/swing/plaf/basic/BasicPasswordFieldUI.java @@ -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 index 00000000000..0f5e761d3d7 --- /dev/null +++ b/libjava/javax/swing/plaf/basic/BasicSpinnerUI.java @@ -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 ComponentUI for the specified + * JComponent + * + * @param c DOCUMENT ME! + * + * @return a ComponentUI + */ + public static ComponentUI createUI(JComponent c) + { + return new BasicSpinnerUI(); + } + + /** + * Creates an editor component. Really, it just returns + * JSpinner.getEditor() + * + * @return a JComponent as an editor + * + * @see javax.swing.JSpinner#getEditor + */ + protected JComponent createEditor() + { + return spinner.getEditor(); + } + + /** + * Creates a LayoutManager 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 PropertyChangeListener that will be attached by + * installListeners. It should watch for the "editor" + * property, when it's changed, replace the old editor with the new one, + * probably by calling replaceEditor + * + * @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 installUI. This should set various defaults + * obtained from UIManager.getLookAndFeelDefaults, as well as + * set the layout obtained from createLayout + * + * @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 installUI, which basically adds the + * PropertyChangeListener created by + * createPropertyChangeListener + * + * @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 JComponent, which in reality, is a + * JSpinner. Calls installDefaults, + * installListeners, 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 installDefaults. Called by + * uninstallUI + */ + protected void uninstallDefaults() + { + spinner.setLayout(null); + } + + /** + * The reverse of installListeners, called by + * uninstallUI + */ + protected void uninstallListeners() + { + spinner.removePropertyChangeListener(listener); + } + + /** + * Called when the current L&F is replaced with another one, should call + * uninstallDefaults and uninstallListeners 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 index 00000000000..c55c9400fa2 --- /dev/null +++ b/libjava/javax/swing/plaf/basic/BasicTableHeaderUI.java @@ -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 index 00000000000..5fa8fb71312 --- /dev/null +++ b/libjava/javax/swing/plaf/basic/BasicTableUI.java @@ -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 index 00000000000..f1714c20d35 --- /dev/null +++ b/libjava/javax/swing/plaf/basic/BasicTextAreaUI.java @@ -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 index 00000000000..3b5941f1bef --- /dev/null +++ b/libjava/javax/swing/plaf/basic/BasicToolTipUI.java @@ -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 index 00000000000..d4ef1f2e598 --- /dev/null +++ b/libjava/javax/swing/plaf/basic/ComboPopup.java @@ -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 index 00000000000..746056dfe7a --- /dev/null +++ b/libjava/javax/swing/text/SimpleAttributeSet.java @@ -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 index 00000000000..2201c47b5b9 --- /dev/null +++ b/libjava/javax/swing/text/StyleConstants.java @@ -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 index 00000000000..8accd9b905b --- /dev/null +++ b/libjava/javax/swing/text/StyleContext.java @@ -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 index 00000000000..58ae65ef096 --- /dev/null +++ b/libjava/javax/swing/text/TabSet.java @@ -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 index 00000000000..2c95a63e4b7 --- /dev/null +++ b/libjava/javax/swing/text/TabStop.java @@ -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 index 00000000000..61c13eef509 --- /dev/null +++ b/libjava/javax/swing/text/Utilities.java @@ -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 + */ +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 Utilities 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 s 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 s 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 index 00000000000..44f2c399438 --- /dev/null +++ b/libjava/jni/gtk-peer/gnu_java_awt_peer_gtk_GThreadNativeMethodRunner.c @@ -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. */ +} + +/* Local Variables: */ +/* c-file-style: "gnu" */ +/* End: */ + +